MonScoDocEssai/app/scodoc/sco_edit_formation.py

283 lines
10 KiB
Python

# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2021 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
#
##############################################################################
"""Ajout/Modification/Supression formations
(portage from DTML)
"""
import notesdb as ndb
import sco_utils as scu
from notes_log import log
from TrivialFormulator import TrivialFormulator, TF, tf_error_message
import sco_codes_parcours
import sco_formsemestre
from sco_exceptions import ScoValueError
import sco_formations
def formation_delete(context, formation_id=None, dialog_confirmed=False, REQUEST=None):
"""Delete a formation"""
F = context.formation_list(args={"formation_id": formation_id})
if not F:
raise ScoValueError("formation inexistante !")
F = F[0]
H = [
html_sco_header.sco_header(
context, REQUEST, page_title="Suppression d'une formation"
),
"""<h2>Suppression de la formation %(titre)s (%(acronyme)s)</h2>""" % F,
]
sems = sco_formsemestre.do_formsemestre_list(
context, {"formation_id": formation_id}
)
if sems:
H.append(
"""<p class="warning">Impossible de supprimer cette formation, car les sessions suivantes l'utilisent:</p>
<ul>"""
)
for sem in sems:
H.append(
'<li><a href="formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titremois)s</a></li>'
% sem
)
H.append('</ul><p><a href="%s">Revenir</a></p>' % scu.NotesURL())
else:
if not dialog_confirmed:
return scu.confirm_dialog(
context,
"""<h2>Confirmer la suppression de la formation %(titre)s (%(acronyme)s) ?</h2>
<p><b>Attention:</b> la suppression d'une formation est <b>irréversible</b> et implique la supression de toutes les UE, matières et modules de la formation !
</p>
"""
% F,
REQUEST=REQUEST,
OK="Supprimer cette formation",
cancel_url=scu.NotesURL(),
parameters={"formation_id": formation_id},
)
else:
context.do_formation_delete(F["formation_id"], REQUEST)
H.append(
"""<p>OK, formation supprimée.</p>
<p><a class="stdlink" href="%s">continuer</a></p>"""
% scu.NotesURL()
)
H.append(html_sco_header.sco_footer(context, REQUEST))
return "\n".join(H)
def formation_create(context, REQUEST=None):
"""Creation d'une formation"""
return formation_edit(context, create=True, REQUEST=REQUEST)
def formation_edit(context, formation_id=None, create=False, REQUEST=None):
"""Edit or create a formation"""
if create:
H = [
html_sco_header.sco_header(
context, REQUEST, page_title="Création d'une formation"
),
"""<h2>Création d'une formation</h2>
<p class="help">Une "formation" décrit une filière, comme un DUT ou une Licence. La formation se subdivise en unités pédagogiques (UE, matières, modules). Elle peut se diviser en plusieurs semestres (ou sessions), qui seront mis en place séparément.
</p>
<p>Le <tt>titre</tt> est le nom complet, parfois adapté pour mieux distinguer les modalités ou versions de programme pédagogique. Le <tt>titre_officiel</tt> est le nom complet du diplôme, qui apparaitra sur certains PV de jury de délivrance du diplôme.
</p>
""",
]
submitlabel = "Créer cette formation"
initvalues = {"type_parcours": sco_codes_parcours.DEFAULT_TYPE_PARCOURS}
is_locked = False
else:
# edit an existing formation
F = context.formation_list(args={"formation_id": formation_id})
if not F:
raise ScoValueError("formation inexistante !")
initvalues = F[0]
is_locked = context.formation_has_locked_sems(formation_id)
submitlabel = "Modifier les valeurs"
H = [
html_sco_header.sco_header(
context, REQUEST, page_title="Modification d'une formation"
),
"""<h2>Modification de la formation %(acronyme)s</h2>""" % initvalues,
]
if is_locked:
H.append(
'<p class="warning">Attention: Formation verrouillée, le type de parcours ne peut être modifié.</p>'
)
tf = TrivialFormulator(
REQUEST.URL0,
REQUEST.form,
(
("formation_id", {"default": formation_id, "input_type": "hidden"}),
(
"acronyme",
{
"size": 12,
"explanation": "identifiant de la formation (par ex. DUT R&T)",
"allow_null": False,
},
),
(
"titre",
{
"size": 80,
"explanation": "nom complet de la formation (ex: DUT Réseaux et Télécommunications",
"allow_null": False,
},
),
(
"titre_officiel",
{
"size": 80,
"explanation": "nom officiel (pour les PV de jury)",
"allow_null": False,
},
),
(
"type_parcours",
{
"input_type": "menu",
"title": "Type de parcours",
"type": "int",
"allowed_values": sco_codes_parcours.FORMATION_PARCOURS_TYPES,
"labels": sco_codes_parcours.FORMATION_PARCOURS_DESCRS,
"explanation": "détermine notamment le nombre de semestres et les règles de validation d'UE et de semestres (barres)",
"readonly": is_locked,
},
),
(
"formation_code",
{
"size": 12,
"title": "Code formation",
"explanation": "code interne. Toutes les formations partageant le même code sont compatibles (compensation de semestres, capitalisation d'UE). Laisser vide si vous ne savez pas, ou entrer le code d'une formation existante.",
},
),
(
"code_specialite",
{
"size": 12,
"title": "Code spécialité",
"explanation": "optionel: code utilisé pour échanger avec d'autres logiciels et identifiant la filière ou spécialité (exemple: ASUR). N'est utilisé que s'il n'y a pas de numéro de semestre.",
},
),
),
initvalues=initvalues,
submitlabel=submitlabel,
)
if tf[0] == 0:
return "\n".join(H) + tf[1] + html_sco_header.sco_footer(context, REQUEST)
elif tf[0] == -1:
return REQUEST.RESPONSE.redirect(scu.NotesURL())
else:
# check unicity : constraint UNIQUE(acronyme,titre,version)
if create:
version = 1
else:
version = initvalues["version"]
args = {
"acronyme": tf[2]["acronyme"],
"titre": tf[2]["titre"],
"version": version,
}
ndb.quote_dict(args)
others = context.formation_list(args=args)
if others and ((len(others) > 1) or others[0]["formation_id"] != formation_id):
return (
"\n".join(H)
+ tf_error_message(
"Valeurs incorrectes: il existe déjà une formation avec même titre, acronyme et version."
)
+ tf[1]
+ html_sco_header.sco_footer(context, REQUEST)
)
#
if create:
formation_id = context.do_formation_create(tf[2], REQUEST)
else:
do_formation_edit(context, tf[2])
return REQUEST.RESPONSE.redirect("ue_list?formation_id=%s" % formation_id)
def do_formation_create(context, args, REQUEST):
"create a formation"
cnx = ndb.GetDBConnexion()
# check unique acronyme/titre/version
a = args.copy()
if a.has_key("formation_id"):
del a["formation_id"]
F = context.formation_list(args=a)
if len(F) > 0:
log("do_formation_create: error: %d formations matching args=%s" % (len(F), a))
raise ScoValueError("Formation non unique (%s) !" % str(a))
# Si pas de formation_code, l'enleve (default SQL)
if args.has_key("formation_code") and not args["formation_code"]:
del args["formation_code"]
#
r = _formationEditor.create(cnx, args)
sco_news.add(
context,
REQUEST,
typ=NEWS_FORM,
text="Création de la formation %(titre)s (%(acronyme)s)" % args,
)
return r
def do_formation_edit(context, args):
"edit a formation"
# log('do_formation_edit( args=%s )'%args)
# On autorise la modif de la formation meme si elle est verrouillee
# car cela ne change que du cosmetique, (sauf eventuellement le code formation ?)
# mais si verrouillée on ne peut changer le type de parcours
if context.formation_has_locked_sems(args["formation_id"]):
if args.has_key("type_parcours"):
del args["type_parcours"]
# On ne peut jamais supprimer le code formation:
if args.has_key("formation_code") and not args["formation_code"]:
del args["formation_code"]
cnx = ndb.GetDBConnexion()
sco_formations._formationEditor.edit(cnx, args)
# Invalide les semestres utilisant cette formation:
for sem in sco_formsemestre.do_formsemestre_list(
context, args={"formation_id": args["formation_id"]}
):
sco_core.inval_cache(
context, formsemestre_id=sem["formsemestre_id"]
) # > formation modif.