forked from ScoDoc/ScoDoc
Merge branch 'dev93' of https://scodoc.org/git/viennet/ScoDoc
This commit is contained in:
commit
97d306d9d0
@ -36,18 +36,21 @@ class Scolog(db.Model):
|
|||||||
class ScolarNews(db.Model):
|
class ScolarNews(db.Model):
|
||||||
"""Nouvelles pour page d'accueil"""
|
"""Nouvelles pour page d'accueil"""
|
||||||
|
|
||||||
NEWS_INSCR = "INSCR" # inscription d'étudiants (object=None ou formsemestre_id)
|
|
||||||
NEWS_NOTE = "NOTES" # saisie note (object=moduleimpl_id)
|
|
||||||
NEWS_FORM = "FORM" # modification formation (object=formation_id)
|
|
||||||
NEWS_SEM = "SEM" # creation semestre (object=None)
|
|
||||||
NEWS_ABS = "ABS" # saisie absence
|
NEWS_ABS = "ABS" # saisie absence
|
||||||
|
NEWS_APO = "APO" # changements de codes APO
|
||||||
|
NEWS_FORM = "FORM" # modification formation (object=formation_id)
|
||||||
|
NEWS_INSCR = "INSCR" # inscription d'étudiants (object=None ou formsemestre_id)
|
||||||
NEWS_MISC = "MISC" # unused
|
NEWS_MISC = "MISC" # unused
|
||||||
|
NEWS_NOTE = "NOTES" # saisie note (object=moduleimpl_id)
|
||||||
|
NEWS_SEM = "SEM" # creation semestre (object=None)
|
||||||
NEWS_MAP = {
|
NEWS_MAP = {
|
||||||
NEWS_INSCR: "inscription d'étudiants",
|
NEWS_ABS: "saisie absence",
|
||||||
NEWS_NOTE: "saisie note",
|
NEWS_APO: "modif. code Apogée",
|
||||||
NEWS_FORM: "modification formation",
|
NEWS_FORM: "modification formation",
|
||||||
NEWS_SEM: "création semestre",
|
NEWS_INSCR: "inscription d'étudiants",
|
||||||
NEWS_MISC: "opération", # unused
|
NEWS_MISC: "opération", # unused
|
||||||
|
NEWS_NOTE: "saisie note",
|
||||||
|
NEWS_SEM: "création semestre",
|
||||||
}
|
}
|
||||||
NEWS_TYPES = list(NEWS_MAP.keys())
|
NEWS_TYPES = list(NEWS_MAP.keys())
|
||||||
|
|
||||||
|
@ -375,7 +375,7 @@ class FormSemestre(db.Model):
|
|||||||
return f"{self.titre} {self.formation.get_parcours().SESSION_NAME} {self.semestre_id}"
|
return f"{self.titre} {self.formation.get_parcours().SESSION_NAME} {self.semestre_id}"
|
||||||
|
|
||||||
def sem_modalite(self) -> str:
|
def sem_modalite(self) -> str:
|
||||||
"""Le semestre et la modialité, ex "S2 FI" ou "S3 APP" """
|
"""Le semestre et la modalité, ex "S2 FI" ou "S3 APP" """
|
||||||
if self.semestre_id > 0:
|
if self.semestre_id > 0:
|
||||||
descr_sem = f"S{self.semestre_id}"
|
descr_sem = f"S{self.semestre_id}"
|
||||||
else:
|
else:
|
||||||
|
@ -486,7 +486,10 @@ class JuryPE(object):
|
|||||||
sesdates = [
|
sesdates = [
|
||||||
pe_tagtable.conversionDate_StrToDate(sem["date_fin"]) for sem in sessems
|
pe_tagtable.conversionDate_StrToDate(sem["date_fin"]) for sem in sessems
|
||||||
] # association 1 date -> 1 semestrePE pour les semestres de l'étudiant
|
] # association 1 date -> 1 semestrePE pour les semestres de l'étudiant
|
||||||
|
if sesdates:
|
||||||
lastdate = max(sesdates) # date de fin de l'inscription la plus récente
|
lastdate = max(sesdates) # date de fin de l'inscription la plus récente
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
# if PETable.AFFICHAGE_DEBUG_PE == True : pe_tools.pe_print(" derniere inscription = ", lastDateSem)
|
# if PETable.AFFICHAGE_DEBUG_PE == True : pe_tools.pe_print(" derniere inscription = ", lastDateSem)
|
||||||
|
|
||||||
@ -585,7 +588,7 @@ class JuryPE(object):
|
|||||||
for (i, fid) in enumerate(lesFids):
|
for (i, fid) in enumerate(lesFids):
|
||||||
if pe_tools.PE_DEBUG:
|
if pe_tools.PE_DEBUG:
|
||||||
pe_tools.pe_print(
|
pe_tools.pe_print(
|
||||||
u"%d) Semestre taggué %s (avec classement dans groupe)"
|
"%d) Semestre taggué %s (avec classement dans groupe)"
|
||||||
% (i + 1, fid)
|
% (i + 1, fid)
|
||||||
)
|
)
|
||||||
self.add_semtags_in_jury(fid)
|
self.add_semtags_in_jury(fid)
|
||||||
@ -620,7 +623,7 @@ class JuryPE(object):
|
|||||||
nbinscrit = self.semTagDict[fid].get_nbinscrits()
|
nbinscrit = self.semTagDict[fid].get_nbinscrits()
|
||||||
if pe_tools.PE_DEBUG:
|
if pe_tools.PE_DEBUG:
|
||||||
pe_tools.pe_print(
|
pe_tools.pe_print(
|
||||||
u" - %d étudiants classés " % (nbinscrit)
|
" - %d étudiants classés " % (nbinscrit)
|
||||||
+ ": "
|
+ ": "
|
||||||
+ ",".join(
|
+ ",".join(
|
||||||
[etudid for etudid in self.semTagDict[fid].get_etudids()]
|
[etudid for etudid in self.semTagDict[fid].get_etudids()]
|
||||||
@ -628,12 +631,12 @@ class JuryPE(object):
|
|||||||
)
|
)
|
||||||
if lesEtudidsManquants:
|
if lesEtudidsManquants:
|
||||||
pe_tools.pe_print(
|
pe_tools.pe_print(
|
||||||
u" - dont %d étudiants manquants ajoutés aux données du jury"
|
" - dont %d étudiants manquants ajoutés aux données du jury"
|
||||||
% (len(lesEtudidsManquants))
|
% (len(lesEtudidsManquants))
|
||||||
+ ": "
|
+ ": "
|
||||||
+ ", ".join(lesEtudidsManquants)
|
+ ", ".join(lesEtudidsManquants)
|
||||||
)
|
)
|
||||||
pe_tools.pe_print(u" - Export csv")
|
pe_tools.pe_print(" - Export csv")
|
||||||
filename = self.NOM_EXPORT_ZIP + self.semTagDict[fid].nom + ".csv"
|
filename = self.NOM_EXPORT_ZIP + self.semTagDict[fid].nom + ".csv"
|
||||||
self.zipfile.writestr(filename, self.semTagDict[fid].str_tagtable())
|
self.zipfile.writestr(filename, self.semTagDict[fid].str_tagtable())
|
||||||
|
|
||||||
@ -742,7 +745,7 @@ class JuryPE(object):
|
|||||||
|
|
||||||
for fid in fids_finaux:
|
for fid in fids_finaux:
|
||||||
if pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 1:
|
if pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 1:
|
||||||
pe_tools.pe_print(u" - semestre final %s" % (fid))
|
pe_tools.pe_print(" - semestre final %s" % (fid))
|
||||||
settag = pe_settag.SetTag(
|
settag = pe_settag.SetTag(
|
||||||
nom, parcours=parcours
|
nom, parcours=parcours
|
||||||
) # Le set tag fusionnant les données
|
) # Le set tag fusionnant les données
|
||||||
@ -762,7 +765,7 @@ class JuryPE(object):
|
|||||||
for ffid in settag.get_Fids_in_settag():
|
for ffid in settag.get_Fids_in_settag():
|
||||||
if pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 1:
|
if pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 1:
|
||||||
pe_tools.pe_print(
|
pe_tools.pe_print(
|
||||||
u" -> ajout du semestre tagué %s" % (ffid)
|
" -> ajout du semestre tagué %s" % (ffid)
|
||||||
)
|
)
|
||||||
self.add_semtags_in_jury(ffid)
|
self.add_semtags_in_jury(ffid)
|
||||||
settag.set_SemTagDict(
|
settag.set_SemTagDict(
|
||||||
@ -791,7 +794,7 @@ class JuryPE(object):
|
|||||||
if nbreEtudInscrits > 0:
|
if nbreEtudInscrits > 0:
|
||||||
if pe_tools.PE_DEBUG:
|
if pe_tools.PE_DEBUG:
|
||||||
pe_tools.pe_print(
|
pe_tools.pe_print(
|
||||||
u"%d) %s avec interclassement sur la promo" % (i + 1, nom)
|
"%d) %s avec interclassement sur la promo" % (i + 1, nom)
|
||||||
)
|
)
|
||||||
if nom in ["S1", "S2", "S3", "S4"]:
|
if nom in ["S1", "S2", "S3", "S4"]:
|
||||||
settag.set_SetTagDict(self.semTagDict)
|
settag.set_SetTagDict(self.semTagDict)
|
||||||
@ -802,7 +805,7 @@ class JuryPE(object):
|
|||||||
else:
|
else:
|
||||||
if pe_tools.PE_DEBUG:
|
if pe_tools.PE_DEBUG:
|
||||||
pe_tools.pe_print(
|
pe_tools.pe_print(
|
||||||
u"%d) Pas d'interclassement %s sur la promo faute de notes"
|
"%d) Pas d'interclassement %s sur la promo faute de notes"
|
||||||
% (i + 1, nom)
|
% (i + 1, nom)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1152,11 +1155,14 @@ class JuryPE(object):
|
|||||||
return sesSems
|
return sesSems
|
||||||
|
|
||||||
# **********************************************
|
# **********************************************
|
||||||
def calcul_anneePromoDUT_d_un_etudiant(self, etudid):
|
def calcul_anneePromoDUT_d_un_etudiant(self, etudid) -> int:
|
||||||
"""Calcule et renvoie la date de diplome prévue pour un étudiant fourni avec son etudid
|
"""Calcule et renvoie la date de diplome prévue pour un étudiant fourni avec son etudid
|
||||||
en fonction de sesSemestres de scolarisation"""
|
en fonction de ses semestres de scolarisation"""
|
||||||
sesSemestres = self.get_semestresDUT_d_un_etudiant(etudid)
|
semestres = self.get_semestresDUT_d_un_etudiant(etudid)
|
||||||
return max([get_annee_diplome_semestre(sem) for sem in sesSemestres])
|
if semestres:
|
||||||
|
return max([get_annee_diplome_semestre(sem) for sem in semestres])
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
# *********************************************
|
# *********************************************
|
||||||
# Fonctions d'affichage pour debug
|
# Fonctions d'affichage pour debug
|
||||||
@ -1184,18 +1190,21 @@ class JuryPE(object):
|
|||||||
chaine += "\n"
|
chaine += "\n"
|
||||||
return chaine
|
return chaine
|
||||||
|
|
||||||
def get_date_entree_etudiant(self, etudid):
|
def get_date_entree_etudiant(self, etudid) -> str:
|
||||||
"""Renvoie la date d'entree d'un étudiant"""
|
"""Renvoie la date d'entree d'un étudiant: "1996" """
|
||||||
return str(
|
annees_debut = [
|
||||||
min([int(sem["annee_debut"]) for sem in self.ETUDINFO_DICT[etudid]["sems"]])
|
int(sem["annee_debut"]) for sem in self.ETUDINFO_DICT[etudid]["sems"]
|
||||||
)
|
]
|
||||||
|
if annees_debut:
|
||||||
|
return str(min(annees_debut))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------
|
||||||
# Fonctions
|
# Fonctions
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------
|
||||||
def get_annee_diplome_semestre(sem):
|
def get_annee_diplome_semestre(sem) -> int:
|
||||||
"""Pour un semestre donne, décrit par le biais du dictionnaire sem usuel :
|
"""Pour un semestre donne, décrit par le biais du dictionnaire sem usuel :
|
||||||
sem = {'formestre_id': ..., 'semestre_id': ..., 'annee_debut': ...},
|
sem = {'formestre_id': ..., 'semestre_id': ..., 'annee_debut': ...},
|
||||||
à condition qu'il soit un semestre de formation DUT,
|
à condition qu'il soit un semestre de formation DUT,
|
||||||
|
@ -385,12 +385,16 @@ class GenTable(object):
|
|||||||
colspan_count = colspan
|
colspan_count = colspan
|
||||||
else:
|
else:
|
||||||
colspan_txt = ""
|
colspan_txt = ""
|
||||||
|
attrs = row.get("_%s_td_attrs" % cid, "")
|
||||||
|
order = row.get(f"_{cid}_order")
|
||||||
|
if order:
|
||||||
|
attrs += f' data-order="{order}"'
|
||||||
r.append(
|
r.append(
|
||||||
"<%s%s %s%s%s>%s</%s>"
|
"<%s%s %s%s%s>%s</%s>"
|
||||||
% (
|
% (
|
||||||
elem,
|
elem,
|
||||||
std,
|
std,
|
||||||
row.get("_%s_td_attrs" % cid, ""),
|
attrs,
|
||||||
klass,
|
klass,
|
||||||
colspan_txt,
|
colspan_txt,
|
||||||
content,
|
content,
|
||||||
|
@ -43,10 +43,8 @@ import app.scodoc.notesdb as ndb
|
|||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc.sco_utils import ModuleType
|
from app.scodoc.sco_utils import ModuleType
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||||
from app.scodoc.gen_tables import GenTable
|
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from app.scodoc.sco_exceptions import (
|
from app.scodoc.sco_exceptions import (
|
||||||
ScoGenError,
|
|
||||||
ScoValueError,
|
ScoValueError,
|
||||||
ScoLockedFormError,
|
ScoLockedFormError,
|
||||||
ScoNonEmptyFormationObject,
|
ScoNonEmptyFormationObject,
|
||||||
@ -61,7 +59,6 @@ from app.scodoc import sco_edit_module
|
|||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_groups
|
from app.scodoc import sco_groups
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
from app.scodoc import sco_preferences
|
|
||||||
from app.scodoc import sco_tag_module
|
from app.scodoc import sco_tag_module
|
||||||
|
|
||||||
_ueEditor = ndb.EditableTable(
|
_ueEditor = ndb.EditableTable(
|
||||||
@ -1355,93 +1352,6 @@ def ue_is_locked(ue_id):
|
|||||||
return len(r) > 0
|
return len(r) > 0
|
||||||
|
|
||||||
|
|
||||||
# ---- Table recap formation
|
|
||||||
def formation_table_recap(formation_id, format="html"):
|
|
||||||
"""Table recapitulant formation."""
|
|
||||||
from app.scodoc import sco_formations
|
|
||||||
|
|
||||||
F = sco_formations.formation_list(args={"formation_id": formation_id})
|
|
||||||
if not F:
|
|
||||||
raise ScoValueError("invalid formation_id")
|
|
||||||
F = F[0]
|
|
||||||
T = []
|
|
||||||
ues = ue_list(args={"formation_id": formation_id})
|
|
||||||
for ue in ues:
|
|
||||||
Matlist = sco_edit_matiere.matiere_list(args={"ue_id": ue["ue_id"]})
|
|
||||||
for Mat in Matlist:
|
|
||||||
Modlist = sco_edit_module.module_list(
|
|
||||||
args={"matiere_id": Mat["matiere_id"]}
|
|
||||||
)
|
|
||||||
for Mod in Modlist:
|
|
||||||
Mod["nb_moduleimpls"] = sco_edit_module.module_count_moduleimpls(
|
|
||||||
Mod["module_id"]
|
|
||||||
)
|
|
||||||
#
|
|
||||||
T.append(
|
|
||||||
{
|
|
||||||
"UE_acro": ue["acronyme"],
|
|
||||||
"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,
|
|
||||||
origin="Généré par %s le " % scu.sco_version.SCONAME
|
|
||||||
+ scu.timedate_human_repr()
|
|
||||||
+ "",
|
|
||||||
caption=title,
|
|
||||||
html_caption=title,
|
|
||||||
html_class="table_leftalign",
|
|
||||||
base_url="%s?formation_id=%s" % (request.base_url, formation_id),
|
|
||||||
page_title=title,
|
|
||||||
html_title="<h2>" + title + "</h2>",
|
|
||||||
pdf_title=title,
|
|
||||||
preferences=sco_preferences.SemPreferences(),
|
|
||||||
)
|
|
||||||
return tab.make_page(format=format)
|
|
||||||
|
|
||||||
|
|
||||||
def ue_list_semestre_ids(ue: dict):
|
def ue_list_semestre_ids(ue: dict):
|
||||||
"""Liste triée des numeros de semestres des modules dans cette UE
|
"""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.
|
Il est recommandable que tous les modules d'une UE aient le même indice de semestre.
|
||||||
|
192
app/scodoc/sco_formation_recap.py
Normal file
192
app/scodoc/sco_formation_recap.py
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gestion scolarite IUT
|
||||||
|
#
|
||||||
|
# Copyright (c) 1999 - 2022 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
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""Table recap formation (avec champs éditables)
|
||||||
|
"""
|
||||||
|
import io
|
||||||
|
from zipfile import ZipFile, BadZipfile
|
||||||
|
|
||||||
|
from flask import send_file, url_for
|
||||||
|
from flask import g, request
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
|
from app.models import Formation, FormSemestre, UniteEns, Module
|
||||||
|
from app.models.formations import Matiere
|
||||||
|
|
||||||
|
from app.scodoc.gen_tables import GenTable
|
||||||
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
from app.scodoc import sco_preferences
|
||||||
|
import app.scodoc.sco_utils as scu
|
||||||
|
|
||||||
|
|
||||||
|
# ---- Table recap formation
|
||||||
|
def formation_table_recap(formation_id, format="html"):
|
||||||
|
"""Table recapitulant formation."""
|
||||||
|
T = []
|
||||||
|
formation = Formation.query.get_or_404(formation_id)
|
||||||
|
ues = formation.ues.order_by(UniteEns.semestre_idx, UniteEns.numero)
|
||||||
|
can_edit = current_user.has_permission(Permission.ScoChangeFormation)
|
||||||
|
li = 0
|
||||||
|
for ue in ues:
|
||||||
|
# L'UE
|
||||||
|
T.append(
|
||||||
|
{
|
||||||
|
"sem": f"S{ue.semestre_idx}" if ue.semestre_idx is not None else "-",
|
||||||
|
"_sem_order": f"{li:04d}",
|
||||||
|
"code": ue.acronyme,
|
||||||
|
"titre": ue.titre or "",
|
||||||
|
"_titre_target": url_for(
|
||||||
|
"notes.ue_edit",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
ue_id=ue.id,
|
||||||
|
)
|
||||||
|
if can_edit
|
||||||
|
else None,
|
||||||
|
"apo": ue.code_apogee or "",
|
||||||
|
"_apo_td_attrs": f""" data-oid="{ue.id}" data-value="{ue.code_apogee or ''}" """,
|
||||||
|
"coef": ue.coefficient or "",
|
||||||
|
"ects": ue.ects,
|
||||||
|
"_css_row_class": f"ue ue_",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
li += 1
|
||||||
|
matieres = ue.matieres.order_by(Matiere.numero)
|
||||||
|
for mat in matieres:
|
||||||
|
modules = mat.modules.order_by(Module.numero)
|
||||||
|
for mod in modules:
|
||||||
|
nb_moduleimpls = mod.modimpls.count()
|
||||||
|
# le module (ou ressource ou sae)
|
||||||
|
T.append(
|
||||||
|
{
|
||||||
|
"sem": f"S{mod.semestre_id}"
|
||||||
|
if mod.semestre_id is not None
|
||||||
|
else "-",
|
||||||
|
"_sem_order": f"{li:04d}",
|
||||||
|
"code": mod.code,
|
||||||
|
"titre": mod.abbrev or mod.titre,
|
||||||
|
"_titre_target": url_for(
|
||||||
|
"notes.module_edit",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
module_id=mod.id,
|
||||||
|
)
|
||||||
|
if can_edit
|
||||||
|
else None,
|
||||||
|
"apo": mod.code_apogee,
|
||||||
|
"_apo_td_attrs": f""" data-oid="{mod.id}" data-value="{mod.code_apogee or ''}" """,
|
||||||
|
"coef": mod.coefficient,
|
||||||
|
"nb_moduleimpls": nb_moduleimpls,
|
||||||
|
"heures_cours": mod.heures_cours,
|
||||||
|
"heures_td": mod.heures_td,
|
||||||
|
"heures_tp": mod.heures_tp,
|
||||||
|
"_css_row_class": f"mod {mod.type_abbrv()}",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
columns_ids = [
|
||||||
|
"sem",
|
||||||
|
"code",
|
||||||
|
"apo",
|
||||||
|
# "mat", inutile d'afficher la matière
|
||||||
|
"titre",
|
||||||
|
"coef",
|
||||||
|
"ects",
|
||||||
|
"nb_moduleimpls",
|
||||||
|
"heures_cours",
|
||||||
|
"heures_td",
|
||||||
|
"heures_tp",
|
||||||
|
]
|
||||||
|
titles = {
|
||||||
|
"ue": "UE",
|
||||||
|
"mat": "Matière",
|
||||||
|
"titre": "Titre",
|
||||||
|
"code": "Code",
|
||||||
|
"apo": "Apo",
|
||||||
|
"coef": "Coef.",
|
||||||
|
"sem": "Sem.",
|
||||||
|
"nb_moduleimpls": "Nb utilisé",
|
||||||
|
"heures_cours": "Cours (h)",
|
||||||
|
"heures_td": "TD (h)",
|
||||||
|
"heures_tp": "TP (h)",
|
||||||
|
"ects": "ECTS",
|
||||||
|
}
|
||||||
|
|
||||||
|
title = f"""Formation {formation.titre} ({formation.acronyme})
|
||||||
|
[version {formation.version}] code {formation.formation_code}"""
|
||||||
|
html_class = "stripe cell-border compact hover order-column formation_table_recap"
|
||||||
|
if current_user.has_permission(Permission.ScoEditApo):
|
||||||
|
html_class += " apo_editable"
|
||||||
|
|
||||||
|
tab = GenTable(
|
||||||
|
columns_ids=columns_ids,
|
||||||
|
rows=T,
|
||||||
|
titles=titles,
|
||||||
|
origin=f"Généré par {scu.sco_version.SCONAME} le {scu.timedate_human_repr()}",
|
||||||
|
caption=title,
|
||||||
|
html_caption=title,
|
||||||
|
html_class=html_class,
|
||||||
|
html_class_ignore_default=True,
|
||||||
|
html_table_attrs=f"""
|
||||||
|
data-apo_ue_save_url="{url_for('notes.ue_set_apo', scodoc_dept=g.scodoc_dept)}"
|
||||||
|
data-apo_mod_save_url="{url_for('notes.module_set_apo', scodoc_dept=g.scodoc_dept)}"
|
||||||
|
""",
|
||||||
|
html_with_td_classes=True,
|
||||||
|
base_url=f"{request.base_url}?formation_id={formation_id}",
|
||||||
|
page_title=title,
|
||||||
|
html_title=f"<h2>{title}</h2>",
|
||||||
|
pdf_title=title,
|
||||||
|
preferences=sco_preferences.SemPreferences(),
|
||||||
|
table_id="formation_table_recap",
|
||||||
|
)
|
||||||
|
return tab.make_page(format=format, javascripts=["js/formation_recap.js"])
|
||||||
|
|
||||||
|
|
||||||
|
def export_recap_formations_annee_scolaire(annee_scolaire):
|
||||||
|
"""Exporte un zip des recap (excel) des formatons de tous les semestres
|
||||||
|
de l'année scolaire indiquée.
|
||||||
|
"""
|
||||||
|
annee_scolaire = int(annee_scolaire)
|
||||||
|
data = io.BytesIO()
|
||||||
|
zip_file = ZipFile(data, "w")
|
||||||
|
formsemestres = FormSemestre.query.filter_by(dept_id=g.scodoc_dept_id).filter(
|
||||||
|
FormSemestre.date_debut >= scu.date_debut_anne_scolaire(annee_scolaire),
|
||||||
|
FormSemestre.date_debut <= scu.date_fin_anne_scolaire(annee_scolaire),
|
||||||
|
)
|
||||||
|
formation_ids = {formsemestre.formation.id for formsemestre in formsemestres}
|
||||||
|
for formation_id in formation_ids:
|
||||||
|
formation = Formation.query.get(formation_id)
|
||||||
|
xls = formation_table_recap(formation_id, format="xlsx").data
|
||||||
|
filename = (
|
||||||
|
scu.sanitize_filename(formation.get_titre_version()) + scu.XLSX_SUFFIX
|
||||||
|
)
|
||||||
|
zip_file.writestr(filename, xls)
|
||||||
|
zip_file.close()
|
||||||
|
data.seek(0)
|
||||||
|
return send_file(
|
||||||
|
data,
|
||||||
|
mimetype="application/zip",
|
||||||
|
download_name=f"formations-{g.scodoc_dept}-{annee_scolaire}-{annee_scolaire+1}.zip",
|
||||||
|
as_attachment=True,
|
||||||
|
)
|
@ -871,6 +871,20 @@ def annee_scolaire_debut(year, month):
|
|||||||
return int(year) - 1
|
return int(year) - 1
|
||||||
|
|
||||||
|
|
||||||
|
def date_debut_anne_scolaire(annee_scolaire: int) -> datetime:
|
||||||
|
"""La date de début de l'année scolaire
|
||||||
|
= 1er aout
|
||||||
|
"""
|
||||||
|
return datetime.datetime(year=annee_scolaire, month=8, day=1)
|
||||||
|
|
||||||
|
|
||||||
|
def date_fin_anne_scolaire(annee_scolaire: int) -> datetime:
|
||||||
|
"""La date de fin de l'année scolaire
|
||||||
|
= 31 juillet de l'année suivante
|
||||||
|
"""
|
||||||
|
return datetime.datetime(year=annee_scolaire + 1, month=7, day=31)
|
||||||
|
|
||||||
|
|
||||||
def sem_decale_str(sem):
|
def sem_decale_str(sem):
|
||||||
"""'D' si semestre decalé, ou ''"""
|
"""'D' si semestre decalé, ou ''"""
|
||||||
# considère "décalé" les semestre impairs commençant entre janvier et juin
|
# considère "décalé" les semestre impairs commençant entre janvier et juin
|
||||||
|
@ -3972,3 +3972,17 @@ table.evaluations_recap td.nb_att,
|
|||||||
table.evaluations_recap td.nb_exc {
|
table.evaluations_recap td.nb_exc {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------- Tableau récap formation ------------ */
|
||||||
|
table.formation_table_recap tr.ue td {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.formation_table_recap td.coef,
|
||||||
|
table.formation_table_recap td.ects,
|
||||||
|
table.formation_table_recap td.nb_moduleimpls,
|
||||||
|
table.formation_table_recap td.heures_cours,
|
||||||
|
table.formation_table_recap td.heures_td,
|
||||||
|
table.formation_table_recap td.heures_tp {
|
||||||
|
text-align: right;
|
||||||
|
}
|
28
app/static/js/formation_recap.js
Normal file
28
app/static/js/formation_recap.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/* Page accueil département */
|
||||||
|
var apo_ue_editor = null;
|
||||||
|
var apo_mod_editor = null;
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
var table_options = {
|
||||||
|
"paging": false,
|
||||||
|
"searching": false,
|
||||||
|
"info": false,
|
||||||
|
/* "autoWidth" : false, */
|
||||||
|
"fixedHeader": {
|
||||||
|
"header": true,
|
||||||
|
"footer": true
|
||||||
|
},
|
||||||
|
"orderCellsTop": true, // cellules ligne 1 pour tri
|
||||||
|
"aaSorting": [], // Prevent initial sorting
|
||||||
|
};
|
||||||
|
$('table#formation_table_recap').DataTable(table_options);
|
||||||
|
let table_editable = document.querySelector("table#formation_table_recap.apo_editable");
|
||||||
|
if (table_editable) {
|
||||||
|
let apo_ue_save_url = document.querySelector("table#formation_table_recap.apo_editable").dataset.apo_ue_save_url;
|
||||||
|
apo_ue_editor = new ScoFieldEditor("table#formation_table_recap tr.ue td.apo", apo_ue_save_url, false);
|
||||||
|
let apo_mod_save_url = document.querySelector("table#formation_table_recap.apo_editable").dataset.apo_mod_save_url;
|
||||||
|
apo_mod_editor = new ScoFieldEditor("table#formation_table_recap tr.mod td.apo", apo_mod_save_url, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
@ -15,8 +15,11 @@ $(document).ready(function () {
|
|||||||
"aaSorting": [], // Prevent initial sorting
|
"aaSorting": [], // Prevent initial sorting
|
||||||
};
|
};
|
||||||
$('table.semlist').DataTable(table_options);
|
$('table.semlist').DataTable(table_options);
|
||||||
|
let table_editable = document.querySelector("table#semlist.apo_editable");
|
||||||
|
if (table_editable) {
|
||||||
let apo_save_url = document.querySelector("table#semlist.apo_editable").dataset.apo_save_url;
|
let apo_save_url = document.querySelector("table#semlist.apo_editable").dataset.apo_save_url;
|
||||||
apo_editor = new ScoFieldEditor(".etapes_apo_str", apo_save_url, false);
|
apo_editor = new ScoFieldEditor(".etapes_apo_str", apo_save_url, false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,11 +45,13 @@ from app.comp import res_sem
|
|||||||
from app.comp.res_compat import NotesTableCompat
|
from app.comp.res_compat import NotesTableCompat
|
||||||
from app.models.formsemestre import FormSemestre
|
from app.models.formsemestre import FormSemestre
|
||||||
from app.models.formsemestre import FormSemestreUEComputationExpr
|
from app.models.formsemestre import FormSemestreUEComputationExpr
|
||||||
|
from app.models.modules import Module
|
||||||
from app.models.ues import UniteEns
|
from app.models.ues import UniteEns
|
||||||
|
|
||||||
from app import api
|
from app import api
|
||||||
from app import db
|
from app import db
|
||||||
from app import models
|
from app import models
|
||||||
|
from app.models import ScolarNews
|
||||||
from app.auth.models import User
|
from app.auth.models import User
|
||||||
from app.but import bulletin_but
|
from app.but import bulletin_but
|
||||||
from app.decorators import (
|
from app.decorators import (
|
||||||
@ -86,7 +88,6 @@ from app.scodoc import sco_archives
|
|||||||
from app.scodoc import sco_bulletins
|
from app.scodoc import sco_bulletins
|
||||||
from app.scodoc import sco_bulletins_pdf
|
from app.scodoc import sco_bulletins_pdf
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_compute_moy
|
|
||||||
from app.scodoc import sco_cost_formation
|
from app.scodoc import sco_cost_formation
|
||||||
from app.scodoc import sco_debouche
|
from app.scodoc import sco_debouche
|
||||||
from app.scodoc import sco_edit_apc
|
from app.scodoc import sco_edit_apc
|
||||||
@ -103,6 +104,7 @@ from app.scodoc import sco_evaluation_edit
|
|||||||
from app.scodoc import sco_evaluation_recap
|
from app.scodoc import sco_evaluation_recap
|
||||||
from app.scodoc import sco_export_results
|
from app.scodoc import sco_export_results
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
|
from app.scodoc import sco_formation_recap
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_formsemestre_custommenu
|
from app.scodoc import sco_formsemestre_custommenu
|
||||||
from app.scodoc import sco_formsemestre_edit
|
from app.scodoc import sco_formsemestre_edit
|
||||||
@ -480,7 +482,14 @@ sco_publish(
|
|||||||
methods=["GET", "POST"],
|
methods=["GET", "POST"],
|
||||||
)
|
)
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/formation_table_recap", sco_edit_ue.formation_table_recap, Permission.ScoView
|
"/formation_table_recap",
|
||||||
|
sco_formation_recap.formation_table_recap,
|
||||||
|
Permission.ScoView,
|
||||||
|
)
|
||||||
|
sco_publish(
|
||||||
|
"/export_recap_formations_annee_scolaire",
|
||||||
|
sco_formation_recap.export_recap_formations_annee_scolaire,
|
||||||
|
Permission.ScoView,
|
||||||
)
|
)
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/formation_add_malus_modules",
|
"/formation_add_malus_modules",
|
||||||
@ -571,6 +580,20 @@ def index_html():
|
|||||||
</li>
|
</li>
|
||||||
<li><a class="stdlink" href="formation_import_xml_form">Importer une formation (xml)</a>
|
<li><a class="stdlink" href="formation_import_xml_form">Importer une formation (xml)</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li><a class="stdlink" href="{
|
||||||
|
url_for("notes.export_recap_formations_annee_scolaire",
|
||||||
|
scodoc_dept=g.scodoc_dept, annee_scolaire=scu.AnneeScolaire()-1)
|
||||||
|
}">exporter les formations de l'année scolaire
|
||||||
|
{scu.AnneeScolaire()-1} - {scu.AnneeScolaire()}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li><a class="stdlink" href="{
|
||||||
|
url_for("notes.export_recap_formations_annee_scolaire",
|
||||||
|
scodoc_dept=g.scodoc_dept, annee_scolaire=scu.AnneeScolaire())
|
||||||
|
}">exporter les formations de l'année scolaire
|
||||||
|
{scu.AnneeScolaire()} - {scu.AnneeScolaire()+1}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h3>Référentiels de compétences</h3>
|
<h3>Référentiels de compétences</h3>
|
||||||
<ul>
|
<ul>
|
||||||
@ -2433,7 +2456,52 @@ def formsemestre_set_apo_etapes():
|
|||||||
formsemestre.etapes.append(etape)
|
formsemestre.etapes.append(etape)
|
||||||
db.session.add(formsemestre)
|
db.session.add(formsemestre)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
ScolarNews.add(
|
||||||
|
typ=ScolarNews.NEWS_APO,
|
||||||
|
text=f"Modification code Apogée du semestre {formsemestre.titre_annee()})",
|
||||||
|
)
|
||||||
|
return ("", 204)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/ue_set_apo", methods=["POST"])
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.ScoEditApo)
|
||||||
|
def ue_set_apo():
|
||||||
|
"""Change le code APO de l'UE
|
||||||
|
Args: oid=ue_id, value=chaine "VRTU12" (1 seul code / UE)
|
||||||
|
"""
|
||||||
|
ue_id = int(request.form.get("oid"))
|
||||||
|
code_apo = (request.form.get("value") or "").strip()
|
||||||
|
ue = UniteEns.query.get_or_404(ue_id)
|
||||||
|
if code_apo != ue.code_apogee:
|
||||||
|
ue.code_apogee = code_apo
|
||||||
|
db.session.add(ue)
|
||||||
|
db.session.commit()
|
||||||
|
ScolarNews.add(
|
||||||
|
typ=ScolarNews.NEWS_FORM,
|
||||||
|
text=f"Modification code Apogée d'UE dans la formation {ue.formation.titre} ({ue.formation.acronyme})",
|
||||||
|
)
|
||||||
|
return ("", 204)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/module_set_apo", methods=["POST"])
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.ScoEditApo)
|
||||||
|
def module_set_apo():
|
||||||
|
"""Change le code APO du module
|
||||||
|
Args: oid=ue_id, value=chaine "VRTU12" (1 seul code / UE)
|
||||||
|
"""
|
||||||
|
oid = int(request.form.get("oid"))
|
||||||
|
code_apo = (request.form.get("value") or "").strip()
|
||||||
|
mod = Module.query.get_or_404(oid)
|
||||||
|
if code_apo != mod.code_apogee:
|
||||||
|
mod.code_apogee = code_apo
|
||||||
|
db.session.add(mod)
|
||||||
|
db.session.commit()
|
||||||
|
ScolarNews.add(
|
||||||
|
typ=ScolarNews.NEWS_FORM,
|
||||||
|
text=f"Modification code Apogée d'UE dans la formation {mod.formation.titre} ({mod.formation.acronyme})",
|
||||||
|
)
|
||||||
return ("", 204)
|
return ("", 204)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.2.5"
|
SCOVERSION = "9.2.6"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user