# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # Gestion scolarite IUT # # Copyright (c) 1999 - 2024 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 matieres (portage from DTML) """ import flask from flask import g, render_template, request, url_for from app import db, log from app.models import Formation, Matiere, UniteEns, ScolarNews import app.scodoc.notesdb as ndb import app.scodoc.sco_utils as scu from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message from app.scodoc.sco_exceptions import ( ScoValueError, ScoLockedFormError, ScoNonEmptyFormationObject, ) _matiereEditor = ndb.EditableTable( "notes_matieres", "matiere_id", ("matiere_id", "ue_id", "numero", "titre"), sortkey="numero", output_formators={"numero": ndb.int_null_is_zero}, ) def matiere_list(*args, **kw): "list matieres" cnx = ndb.GetDBConnexion() return _matiereEditor.list(cnx, *args, **kw) def do_matiere_edit(*args, **kw): "edit a matiere" from app.formations import edit_ue cnx = ndb.GetDBConnexion() # check mat = matiere_list({"matiere_id": args[0]["matiere_id"]})[0] if matiere_is_locked(mat["matiere_id"]): raise ScoLockedFormError() # edit _matiereEditor.edit(cnx, *args, **kw) formation_id = edit_ue.ue_list({"ue_id": mat["ue_id"]})[0]["formation_id"] db.session.get(Formation, formation_id).invalidate_cached_sems() def do_matiere_create(args): "create a matiere" from app.formations import edit_ue cnx = ndb.GetDBConnexion() # check ue = edit_ue.ue_list({"ue_id": args["ue_id"]})[0] # create matiere r = _matiereEditor.create(cnx, args) # news formation = db.session.get(Formation, ue["formation_id"]) ScolarNews.add( typ=ScolarNews.NEWS_FORM, obj=ue["formation_id"], text=f"Modification de la formation {formation.acronyme}", ) formation.invalidate_cached_sems() return r def matiere_create(ue_id=None): """Creation d'une matiere""" ue: UniteEns = UniteEns.query.get_or_404(ue_id) default_numero = max([mat.numero for mat in ue.matieres] or [9]) + 1 H = [ f"""
Les matières sont des groupes de modules dans une UE d'une formation donnée. Les matières servent surtout pour la présentation (bulletins, etc) mais n'ont pas de rôle dans le calcul des notes.
Si votre formation n'utilise pas la notion de "matières", créez une matière par UE, et donnez lui le même nom que l'UE (en effet, tout module doit appartenir à une matière).
Comme les UE, les matières n'ont pas de coefficient associé.
""", ] tf = TrivialFormulator( request.base_url, scu.get_request_args(), ( ("ue_id", {"input_type": "hidden", "default": ue_id}), ( "titre", { "size": 30, "explanation": "nom de la matière.", }, ), ( "numero", { "size": 2, "explanation": "numéro (1,2,3,4...) pour affichage", "type": "int", "default": default_numero, "allow_null": False, }, ), ), submitlabel="Créer cette matière", ) dest_url = url_for( "notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=ue.formation_id ) if tf[0] == 0: return render_template( "sco_page.j2", title="Création d'une matière", content="\n".join(H) + tf[1] ) if tf[0] == -1: return flask.redirect(dest_url) # check unicity mats = matiere_list(args={"ue_id": ue_id, "titre": tf[2]["titre"]}) if mats: return render_template( "sco_page.j2", title="Création d'une matière", content=( "\n".join(H) + tf_error_message("Titre de matière déjà existant dans cette UE") + tf[1] ), ) _ = do_matiere_create(tf[2]) return flask.redirect(dest_url) def can_delete_matiere(matiere: Matiere) -> tuple[bool, str]: "True si la matiere n'est pas utilisée dans des formsemestre" locked = matiere_is_locked(matiere.id) if locked: return False if any(m.modimpls.all() for m in matiere.modules): return False return True def do_matiere_delete(oid): "delete matiere and attached modules" from app.formations import edit_module, edit_ue cnx = ndb.GetDBConnexion() # check matiere = Matiere.query.get_or_404(oid) mat = matiere_list({"matiere_id": oid})[0] # compat sco7 ue = edit_ue.ue_list({"ue_id": mat["ue_id"]})[0] if not can_delete_matiere(matiere): # il y a au moins un modimpl dans un module de cette matière raise ScoNonEmptyFormationObject("Matière", matiere.titre) log(f"do_matiere_delete: matiere_id={matiere.id}") # delete all modules in this matiere mods = edit_module.module_list({"matiere_id": matiere.id}) for mod in mods: edit_module.do_module_delete(mod["module_id"]) _matiereEditor.delete(cnx, oid) # news formation = db.session.get(Formation, ue["formation_id"]) ScolarNews.add( typ=ScolarNews.NEWS_FORM, obj=ue["formation_id"], text=f"Modification de la formation {formation.acronyme}", ) formation.invalidate_cached_sems() def matiere_delete(matiere_id=None): """Delete matière""" from app.formations import edit_ue matiere = Matiere.query.get_or_404(matiere_id) if not can_delete_matiere(matiere): # il y a au moins un modimpl dans un module de cette matière raise ScoNonEmptyFormationObject( "Matière", matiere.titre, dest_url=url_for( "notes.ue_table", formation_id=matiere.ue.formation_id, semestre_idx=matiere.ue.semestre_idx, scodoc_dept=g.scodoc_dept, ), ) mat = matiere_list(args={"matiere_id": matiere_id})[0] ue_dict = edit_ue.ue_list(args={"ue_id": mat["ue_id"]})[0] H = [ "Les matières sont des groupes de modules dans une UE d'une formation donnée. Les matières servent surtout pour la présentation (bulletins, etc) mais n'ont pas de rôle dans le calcul des notes.
Si votre formation n'utilise pas la notion de "matières", créez une matière par UE, et donnez lui le même nom que l'UE (en effet, tout module doit appartenir à une matière).
Comme les UE, les matières n'ont pas de coefficient associé.
""" tf = TrivialFormulator( request.base_url, scu.get_request_args(), ( ("matiere_id", {"input_type": "hidden"}), ( "ue_id", { "input_type": "menu", "allowed_values": ue_ids, "labels": ue_names, "title": "UE", }, ), ("titre", {"size": 30, "explanation": "nom de cette matière"}), ( "numero", { "size": 2, "explanation": "numéro (1,2,3,4...) pour affichage", "type": "int", }, ), ), initvalues=F, submitlabel="Modifier les valeurs", ) dest_url = url_for( "notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=str(ue["formation_id"]), ) if tf[0] == 0: return render_template( "sco_page.j2", title="Modification d'une matière", content="\n".join(H) + tf[1] + help_msg, ) elif tf[0] == -1: return flask.redirect(dest_url) else: # check unicity mats = matiere_list(args={"ue_id": tf[2]["ue_id"], "titre": tf[2]["titre"]}) if len(mats) > 1 or (len(mats) == 1 and mats[0]["matiere_id"] != matiere_id): return render_template( "sco_page.j2", title="Modification d'une matière", content=( "\n".join(H) + tf_error_message("Titre de matière déjà existant dans cette UE") + tf[1] ), ) # changement d'UE ? if tf[2]["ue_id"] != F["ue_id"]: log("attaching mat %s to new UE %s" % (matiere_id, tf[2]["ue_id"])) ndb.SimpleQuery( "UPDATE notes_modules SET ue_id = %(ue_id)s WHERE matiere_id=%(matiere_id)s", {"ue_id": tf[2]["ue_id"], "matiere_id": matiere_id}, ) do_matiere_edit(tf[2]) return flask.redirect(dest_url) def matiere_is_locked(matiere_id): """True if matiere should not be modified (contains modules used in a locked formsemestre) """ r = ndb.SimpleDictFetch( """SELECT ma.id FROM notes_matieres ma, notes_modules mod, notes_formsemestre sem, notes_moduleimpl mi WHERE ma.id = mod.matiere_id AND mi.module_id = mod.id AND mi.formsemestre_id = sem.id AND ma.id = %(matiere_id)s AND sem.etat = false """, {"matiere_id": matiere_id}, ) return len(r) > 0