# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # ScoDoc # # 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 # ############################################################################## """ PN / Edition des coefs Emmanuel Viennet, 2021 """ from flask import url_for from flask import g, request from flask_json import as_json from flask_login import current_user from flask.templating import render_template from app.scodoc.codes_cursus import UE_SPORT from app import db, models from app.comp import moy_ue from app.decorators import scodoc, permission_required from app.models import ApcParcours, Formation, Module from app.views import notes_bp as bp from app.scodoc import html_sco_header from app.scodoc import sco_utils as scu from app.scodoc.sco_permissions import Permission @bp.route("/table_modules_ue_coefs/<int:formation_id>") @bp.route("/table_modules_ue_coefs/<int:formation_id>/<int:semestre_idx>") @bp.route( "/table_modules_ue_coefs/<int:formation_id>/<int:semestre_idx>/<int:parcours_id>" ) @scodoc @permission_required(Permission.ScoView) @as_json def table_modules_ue_coefs(formation_id, semestre_idx=None, parcours_id: int = None): """Description JSON de la table des coefs modules/UE dans une formation Si le parcours est indiqué et que la formation a un référentiel de compétence, restreint l'affichage aux UE et modules de ce parcours. """ formation: Formation = models.Formation.query.get_or_404(formation_id) # check if semestre_idx == "": semestre_idx = None if parcours_id == "": parcours_id = None if parcours_id is not None and formation.referentiel_competence is not None: parcour: ApcParcours = ApcParcours.query.get_or_404(parcours_id) else: parcour = None df, ues, modules = moy_ue.df_load_module_coefs(formation_id, semestre_idx) # Filtrage par parcours if parcour is not None: ues = [ ue for ue in ues if (parcours_id in (p.id for p in ue.parcours)) or (not ue.parcours) ] modules = [ mod for mod in modules if ((parcours_id in (p.id for p in mod.parcours)) or (mod.parcours is None)) and mod.module_type in (scu.ModuleType.RESSOURCE, scu.ModuleType.SAE) ] else: # ne montre que les ressources et SAE (pas le bonus...) modules = [ mod for mod in modules if mod.module_type in (scu.ModuleType.RESSOURCE, scu.ModuleType.SAE) ] # Titre des modules, en ligne col_titres_mods = [ { "x": 1, # 1ere colonne "y": row, # "nbX": 1, # "nbY": 1, "style": "title_mod title_" + scu.ModuleType(mod.module_type).name, "data": mod.code, "title": mod.titre, } for (row, mod) in enumerate(modules, start=2) ] row_titres_ue = [ { "x": col, "y": 1, # 1ere ligne "style": "title_ue", "data": ue.acronyme, "title": ue.titre or ue.acronymexs, } for (col, ue) in enumerate(ues, start=2) ] # Les champs de saisie cells = [] for row, mod in enumerate(modules, start=2): style = "champs champs_" + scu.ModuleType(mod.module_type).name mod_parcours_ids = {p.id for p in mod.parcours} for col, ue in enumerate(ues, start=2): # met en gris les coefs qui devraient être nuls # car le module n'est pas dans le parcours de l'UE: if ( mod.parcours and ue.parcours and not {p.id for p in ue.parcours}.intersection(mod_parcours_ids) ): cell_style = style + " champs_coef_hors_parcours" else: cell_style = style cells.append( { "x": col, "y": row, "style": cell_style, "data": df[mod.id][ue.id] or "", "editable": mod.ue.type != UE_SPORT, "module_id": mod.id, "ue_id": ue.id, } ) return col_titres_mods + row_titres_ue + cells @bp.route("/set_module_ue_coef", methods=["POST"]) @scodoc @permission_required(Permission.EditFormation) def set_module_ue_coef(): """Set coef from module to UE""" try: module_id = int(request.form["module_id"]) except ValueError: return scu.json_error(404, "invalid module_id") try: ue_id = int(request.form["ue_id"]) except ValueError: return scu.json_error(404, "invalid ue_id") try: coef = float(request.form["coef"].replace(",", ".")) except ValueError: return scu.json_error(404, "invalid coef") module: Module = db.session.get(Module, module_id) if module is None: return scu.json_error(404, f"module not found ({module_id})") ue = db.session.get(models.UniteEns, ue_id) if not ue: return scu.json_error(404, f"UE not found ({ue_id})") module.set_ue_coef(ue, coef) db.session.commit() module.formation.invalidate_cached_sems() return scu.json_ok_response(201) @bp.route("/edit_modules_ue_coefs") @scodoc @permission_required(Permission.ScoView) def edit_modules_ue_coefs(): """Formulaire édition grille coefs EU/modules""" formation_id = int(request.args["formation_id"]) semestre_idx = request.args.get("semestre_idx", "") parcours_id = request.args.get("parcours_id") if parcours_id == "": parcours_id = None if parcours_id is not None: parcours_id = int(parcours_id) if len(semestre_idx.strip()) > 0: semestre_idx = int(semestre_idx) else: semestre_idx = None formation = models.Formation.query.filter_by( formation_id=formation_id ).first_or_404() locked = formation.has_locked_sems(semestre_idx) if locked: lockicon = scu.icontag("lock32_img", title="verrouillé") else: lockicon = "" H = [ html_sco_header.sco_header( cssstyles=["css/table_editor.css"], javascripts=[ "js/table_editor.js", ], page_title=f"Coefs programme {formation.acronyme}", ), f"""<h2>Formation {formation.titre} ({formation.acronyme}) [version {formation.version}] code {formation.formation_code} {lockicon} </h2> """, ( """<span class="warning">Formation verrouilée car un ou plusieurs semestres verrouillés l'utilisent. </span>""" if locked else "" ), render_template( "pn/form_modules_ue_coefs.j2", formation=formation, data_source=url_for( "notes.table_modules_ue_coefs", scodoc_dept=g.scodoc_dept, formation_id=formation_id, semestre_idx=semestre_idx, parcours_id=parcours_id, ), data_save=url_for( "notes.set_module_ue_coef", scodoc_dept=g.scodoc_dept, ), read_only=locked or not current_user.has_permission(Permission.EditFormation), semestre_idx=semestre_idx, semestre_ids=range(1, formation.get_cursus().NB_SEM + 1), parcours_id=parcours_id, ), html_sco_header.sco_footer(), ] return "\n".join(H)