forked from ScoDoc/ScoDoc
Merge branch 'master' of https://scodoc.org/git/viennet/ScoDoc into xp
This commit is contained in:
commit
e2141b6505
@ -502,12 +502,10 @@ def clear_scodoc_cache():
|
||||
|
||||
|
||||
# --------- Logging
|
||||
def log(msg: str, silent_test=True):
|
||||
def log(msg: str):
|
||||
"""log a message.
|
||||
If Flask app, use configured logger, else stderr.
|
||||
"""
|
||||
if silent_test and current_app and current_app.config["TESTING"]:
|
||||
return
|
||||
try:
|
||||
dept = getattr(g, "scodoc_dept", "")
|
||||
msg = f" ({dept}) {msg}"
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
"""ScoDoc 9 API : Absences
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
"""ScoDoc 9 API : outils
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
@ -361,7 +361,7 @@ class BulletinBUT:
|
||||
"formsemestre_id": formsemestre.id,
|
||||
"etat_inscription": etat_inscription,
|
||||
"options": sco_preferences.bulletin_option_affichage(
|
||||
formsemestre.id, self.prefs
|
||||
formsemestre, self.prefs
|
||||
),
|
||||
}
|
||||
if not published:
|
||||
@ -465,6 +465,7 @@ class BulletinBUT:
|
||||
"ressources": {},
|
||||
"saes": {},
|
||||
"ues": {},
|
||||
"ues_capitalisees": {},
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
from xml.etree import ElementTree
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
@ -91,9 +91,15 @@ from app.models.ues import UniteEns
|
||||
from app.models.validations import ScolarFormSemestreValidation
|
||||
from app.scodoc import sco_cache
|
||||
from app.scodoc import sco_codes_parcours as sco_codes
|
||||
from app.scodoc.sco_codes_parcours import CODES_UE_VALIDES, RED, UE_STANDARD
|
||||
from app.scodoc.sco_codes_parcours import (
|
||||
BUT_CODES_ORDERED,
|
||||
CODES_RCUE_VALIDES,
|
||||
CODES_UE_VALIDES,
|
||||
RED,
|
||||
UE_STANDARD,
|
||||
)
|
||||
from app.scodoc import sco_utils as scu
|
||||
from app.scodoc.sco_exceptions import ScoException, ScoValueError
|
||||
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences, ScoValueError
|
||||
|
||||
|
||||
class NoRCUEError(ScoValueError):
|
||||
@ -170,7 +176,7 @@ class DecisionsProposees:
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"""<{self.__class__.__name__} valid={self.code_valide
|
||||
} codes={self.codes} explanation={self.explanation}"""
|
||||
} codes={self.codes} explanation={self.explanation}>"""
|
||||
|
||||
|
||||
class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
@ -205,6 +211,8 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
formsemestre: FormSemestre,
|
||||
):
|
||||
assert formsemestre.formation.is_apc()
|
||||
if formsemestre.formation.referentiel_competence is None:
|
||||
raise ScoNoReferentielCompetences(formation=formsemestre.formation)
|
||||
super().__init__(etud=etud)
|
||||
self.formsemestre = formsemestre
|
||||
"le formsemestre utilisé pour construire ce deca"
|
||||
@ -348,8 +356,9 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
)
|
||||
"vrai si l'année est réussie, tous niveaux validables ou validés par le jury"
|
||||
self.valide_moitie_rcue = self.nb_validables > (self.nb_competences // 2)
|
||||
"Peut passer si plus de la moitié validables et tous > 8"
|
||||
"Vrai si plus de la moitié des RCUE validables"
|
||||
self.passage_de_droit = self.valide_moitie_rcue and (self.nb_rcues_under_8 == 0)
|
||||
"Vrai si peut passer dans l'année BUT suivante: plus de la moitié validables et tous > 8"
|
||||
# XXX TODO ajouter condition pour passage en S5
|
||||
|
||||
# Enfin calcule les codes des UE:
|
||||
@ -362,7 +371,6 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
"s" if plural else ""} sur {self.nb_competences}"""
|
||||
if self.admis:
|
||||
self.codes = [sco_codes.ADM] + self.codes
|
||||
self.explanation = expl_rcues
|
||||
# elif not self.jury_annuel:
|
||||
# self.codes = [] # pas de décision annuelle sur semestres impairs
|
||||
elif self.inscription_etat != scu.INSCRIT:
|
||||
@ -378,9 +386,9 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
sco_codes.ABL,
|
||||
sco_codes.EXCLU,
|
||||
]
|
||||
expl_rcues = ""
|
||||
elif self.passage_de_droit:
|
||||
self.codes = [sco_codes.PASD, sco_codes.ADJ] + self.codes
|
||||
self.explanation = expl_rcues
|
||||
elif self.valide_moitie_rcue: # mais au moins 1 rcue insuffisante
|
||||
self.codes = [
|
||||
sco_codes.RED,
|
||||
@ -388,7 +396,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
sco_codes.PAS1NCI,
|
||||
sco_codes.ADJ,
|
||||
] + self.codes
|
||||
self.explanation = expl_rcues + f" et {self.nb_rcues_under_8} < 8"
|
||||
expl_rcues += f" et {self.nb_rcues_under_8} < 8"
|
||||
else:
|
||||
self.codes = [
|
||||
sco_codes.RED,
|
||||
@ -397,17 +405,21 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
sco_codes.ADJ,
|
||||
sco_codes.PASD, # voir #488 (discutable, conventions locales)
|
||||
] + self.codes
|
||||
self.explanation = (
|
||||
expl_rcues
|
||||
+ f""" et {self.nb_rcues_under_8}
|
||||
niveau{'x' if self.nb_rcues_under_8 > 1 else ''} < 8"""
|
||||
)
|
||||
expl_rcues += f""" et {self.nb_rcues_under_8} niveau{'x' if self.nb_rcues_under_8 > 1 else ''} < 8"""
|
||||
|
||||
# Si l'un des semestres est extérieur, propose ADM
|
||||
if (
|
||||
self.formsemestre_impair and self.formsemestre_impair.modalite == "EXT"
|
||||
) or (self.formsemestre_pair and self.formsemestre_pair.modalite == "EXT"):
|
||||
self.codes.insert(0, sco_codes.ADM)
|
||||
|
||||
self.explanation = f"<div>{expl_rcues}</div>"
|
||||
messages = self.descr_pb_coherence()
|
||||
if messages:
|
||||
self.explanation += (
|
||||
'<div class="warning">'
|
||||
+ '</div><div class="warning">'.join(messages)
|
||||
+ "</div>"
|
||||
)
|
||||
#
|
||||
|
||||
def infos(self) -> str:
|
||||
@ -581,9 +593,10 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
|
||||
def compute_decisions_niveaux(self) -> dict[int, "DecisionsProposeesRCUE"]:
|
||||
"""Pour chaque niveau de compétence de cette année, construit
|
||||
le DecisionsProposeesRCUE,
|
||||
ou None s'il n'y en a pas
|
||||
le DecisionsProposeesRCUE, ou None s'il n'y en a pas
|
||||
(ne devrait pas arriver car compute_rcues_annee vérifie déjà cela).
|
||||
|
||||
Appelé à la construction du deca, donc avant décisions manuelles.
|
||||
Return: { niveau_id : DecisionsProposeesRCUE }
|
||||
"""
|
||||
# Retrouve le RCUE associé à chaque niveau
|
||||
@ -630,6 +643,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
|
||||
def record_form(self, form: dict):
|
||||
"""Enregistre les codes de jury en base
|
||||
à partir d'un dict représentant le formulaire jury BUT:
|
||||
form dict:
|
||||
- 'code_ue_1896' : 'AJ' code pour l'UE id 1896
|
||||
- 'code_rcue_6" : 'ADM' code pour le RCUE du niveau 6
|
||||
@ -639,32 +653,42 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
et qu'il n'y en a pas déjà, enregistre ceux par défaut.
|
||||
"""
|
||||
log("jury_but.DecisionsProposeesAnnee.record_form")
|
||||
with sco_cache.DeferredSemCacheManager():
|
||||
for key in form:
|
||||
code = form[key]
|
||||
# Codes d'UE
|
||||
m = re.match(r"^code_ue_(\d+)$", key)
|
||||
code_annee = None
|
||||
codes_rcues = [] # [ (dec_rcue, code), ... ]
|
||||
codes_ues = [] # [ (dec_ue, code), ... ]
|
||||
for key in form:
|
||||
code = form[key]
|
||||
# Codes d'UE
|
||||
m = re.match(r"^code_ue_(\d+)$", key)
|
||||
if m:
|
||||
ue_id = int(m.group(1))
|
||||
dec_ue = self.decisions_ues.get(ue_id)
|
||||
if not dec_ue:
|
||||
raise ScoValueError(f"UE invalide ue_id={ue_id}")
|
||||
codes_ues.append((dec_ue, code))
|
||||
else:
|
||||
# Codes de RCUE
|
||||
m = re.match(r"^code_rcue_(\d+)$", key)
|
||||
if m:
|
||||
ue_id = int(m.group(1))
|
||||
dec_ue = self.decisions_ues.get(ue_id)
|
||||
if not dec_ue:
|
||||
raise ScoValueError(f"UE invalide ue_id={ue_id}")
|
||||
dec_ue.record(code)
|
||||
else:
|
||||
# Codes de RCUE
|
||||
m = re.match(r"^code_rcue_(\d+)$", key)
|
||||
if m:
|
||||
niveau_id = int(m.group(1))
|
||||
dec_rcue = self.decisions_rcue_by_niveau.get(niveau_id)
|
||||
if not dec_rcue:
|
||||
raise ScoValueError(f"RCUE invalide niveau_id={niveau_id}")
|
||||
dec_rcue.record(code)
|
||||
elif key == "code_annee":
|
||||
# Code annuel
|
||||
self.record(code)
|
||||
niveau_id = int(m.group(1))
|
||||
dec_rcue = self.decisions_rcue_by_niveau.get(niveau_id)
|
||||
if not dec_rcue:
|
||||
raise ScoValueError(f"RCUE invalide niveau_id={niveau_id}")
|
||||
codes_rcues.append((dec_rcue, code))
|
||||
elif key == "code_annee":
|
||||
# Code annuel
|
||||
code_annee = code
|
||||
|
||||
with sco_cache.DeferredSemCacheManager():
|
||||
# Enregistre les codes, dans l'ordre UE, RCUE, Année
|
||||
for dec_ue, code in codes_ues:
|
||||
dec_ue.record(code)
|
||||
for dec_rcue, code in codes_rcues:
|
||||
dec_rcue.record(code)
|
||||
self.record(code_annee)
|
||||
self.record_all()
|
||||
db.session.commit()
|
||||
|
||||
db.session.commit()
|
||||
|
||||
def record(self, code: str, no_overwrite=False):
|
||||
"""Enregistre le code de l'année, et au besoin l'autorisation d'inscription.
|
||||
@ -682,7 +706,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
return # no change
|
||||
if self.validation:
|
||||
db.session.delete(self.validation)
|
||||
db.session.flush()
|
||||
db.session.commit()
|
||||
if code is None:
|
||||
self.validation = None
|
||||
else:
|
||||
@ -693,12 +717,15 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
annee_scolaire=self.annee_scolaire(),
|
||||
code=code,
|
||||
)
|
||||
db.session.add(self.validation)
|
||||
db.session.commit()
|
||||
log(f"Recording {self}: {code}")
|
||||
Scolog.logdb(
|
||||
method="jury_but",
|
||||
etudid=self.etud.id,
|
||||
msg=f"Validation année BUT{self.annee_but}: {code}",
|
||||
)
|
||||
db.session.add(self.validation)
|
||||
|
||||
# --- Autorisation d'inscription dans semestre suivant ?
|
||||
if self.formsemestre_pair is not None:
|
||||
if code is None:
|
||||
@ -729,29 +756,49 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
if self.formsemestre_pair is not None:
|
||||
sco_cache.invalidate_formsemestre(formsemestre_id=self.formsemestre_pair.id)
|
||||
|
||||
def record_all(self):
|
||||
def record_all(self, no_overwrite: bool = True):
|
||||
"""Enregistre les codes qui n'ont pas été spécifiés par le formulaire,
|
||||
et sont donc en mode "automatique"
|
||||
et sont donc en mode "automatique".
|
||||
- Si "à cheval", ne modifie pas les codes UE de l'année scolaire précédente.
|
||||
- Pour les RCUE: n'enregistre que si la nouvelle décision est plus favorable que l'ancienne.
|
||||
"""
|
||||
decisions = (
|
||||
list(self.decisions_ues.values())
|
||||
+ list(self.decisions_rcue_by_niveau.values())
|
||||
+ [self]
|
||||
)
|
||||
for dec in decisions:
|
||||
if not dec.recorded:
|
||||
# Toujours valider dans l'ordre UE, RCUE, Année:
|
||||
annee_scolaire = self.formsemestre.annee_scolaire()
|
||||
# UEs
|
||||
for dec_ue in self.decisions_ues.values():
|
||||
if (
|
||||
not dec_ue.recorded
|
||||
) and dec_ue.formsemestre.annee_scolaire() == annee_scolaire:
|
||||
# rappel: le code par défaut est en tête
|
||||
code = dec.codes[0] if dec.codes else None
|
||||
code = dec_ue.codes[0] if dec_ue.codes else None
|
||||
# enregistre le code jury seulement s'il n'y a pas déjà de code
|
||||
dec.record(code, no_overwrite=True)
|
||||
# (no_overwrite=True) sauf en mode test yaml
|
||||
dec_ue.record(code, no_overwrite=no_overwrite)
|
||||
# RCUE : enregistre seulement si pas déjà validé "mieux"
|
||||
for dec_rcue in self.decisions_rcue_by_niveau.values():
|
||||
code = dec_rcue.codes[0] if dec_rcue.codes else None
|
||||
if (not dec_rcue.recorded) and (
|
||||
(not dec_rcue.validation)
|
||||
or BUT_CODES_ORDERED.get(dec_rcue.validation.code, 0)
|
||||
< BUT_CODES_ORDERED.get(code, 0)
|
||||
):
|
||||
dec_rcue.record(code, no_overwrite=no_overwrite)
|
||||
# Année:
|
||||
if not self.recorded:
|
||||
# rappel: le code par défaut est en tête
|
||||
code = self.codes[0] if self.codes else None
|
||||
# enregistre le code jury seulement s'il n'y a pas déjà de code
|
||||
# (no_overwrite=True) sauf en mode test yaml
|
||||
self.record(code, no_overwrite=no_overwrite)
|
||||
|
||||
def erase(self, only_one_sem=False):
|
||||
"""Efface les décisions de jury de cet étudiant
|
||||
pour cette année: décisions d'UE, de RCUE, d'année,
|
||||
et autorisations d'inscription émises.
|
||||
Efface même si étudiant DEM ou DEF.
|
||||
Si à cheval, n'efface que pour le semestre d'origine du deca.
|
||||
"""
|
||||
if only_one_sem:
|
||||
if only_one_sem or self.a_cheval:
|
||||
# N'efface que les autorisations venant de ce semestre,
|
||||
# et les validations de ses UEs
|
||||
ScolarAutorisationInscription.delete_autorisation_etud(
|
||||
@ -779,13 +826,23 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
ordre=self.annee_but,
|
||||
)
|
||||
for validation in validations:
|
||||
db.session.delete(validation)
|
||||
Scolog.logdb(
|
||||
"jury_but",
|
||||
etudid=self.etud.id,
|
||||
msg=f"Validation année BUT{self.annee_but}: effacée",
|
||||
)
|
||||
db.session.delete(validation)
|
||||
db.session.flush()
|
||||
|
||||
# Efface éventuelles validations de semestre
|
||||
# (en principe inutilisées en BUT)
|
||||
# et autres UEs (en cas de changement d'architecture de formation depuis le jury ?)
|
||||
#
|
||||
for validation in ScolarFormSemestreValidation.query.filter_by(
|
||||
etudid=self.etud.id, formsemestre_id=self.formsemestre_id
|
||||
):
|
||||
db.session.delete(validation)
|
||||
|
||||
db.session.commit()
|
||||
self.invalidate_formsemestre_cache()
|
||||
|
||||
def get_autorisations_passage(self) -> list[int]:
|
||||
@ -828,6 +885,27 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
validations.append(", ".join(v for v in valids if v))
|
||||
return line_sep.join(validations)
|
||||
|
||||
def descr_pb_coherence(self) -> list[str]:
|
||||
"""Description d'éventuels problèmes de cohérence entre
|
||||
les décisions *enregistrées* d'UE et de RCUE.
|
||||
Note: en principe, la cohérence RCUE/UE est assurée au moment de
|
||||
l'enregistrement (record).
|
||||
Mais la base peut avoir été modifiée par d'autres voies.
|
||||
"""
|
||||
messages = []
|
||||
for dec_rcue in self.decisions_rcue_by_niveau.values():
|
||||
if dec_rcue.code_valide in CODES_RCUE_VALIDES:
|
||||
for ue in (dec_rcue.rcue.ue_1, dec_rcue.rcue.ue_2):
|
||||
dec_ue = self.decisions_ues.get(ue.id)
|
||||
if dec_ue:
|
||||
if dec_ue.code_valide not in CODES_UE_VALIDES:
|
||||
messages.append(
|
||||
f"L'UE {ue.acronyme} n'est pas validée mais son RCUE l'est !"
|
||||
)
|
||||
else:
|
||||
messages.append(f"L'UE {ue.acronyme} n'a pas décision (???)")
|
||||
return messages
|
||||
|
||||
|
||||
def list_ue_parcour_etud(
|
||||
formsemestre: FormSemestre, etud: Identite, res: ResultatsSemestreBUT
|
||||
@ -873,6 +951,7 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
||||
inscription_etat: str = scu.INSCRIT,
|
||||
):
|
||||
super().__init__(etud=dec_prop_annee.etud)
|
||||
self.deca = dec_prop_annee
|
||||
self.rcue = rcue
|
||||
if rcue is None: # RCUE non dispo, eg un seul semestre
|
||||
self.codes = []
|
||||
@ -904,9 +983,30 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
||||
or dec_prop_annee.formsemestre_pair.modalite == "EXT"
|
||||
):
|
||||
self.codes.insert(0, sco_codes.ADM)
|
||||
# S'il y a une décision enregistrée: si elle est plus favorable que celle que l'on
|
||||
# proposerait, la place en tête.
|
||||
# Sinon, la place en seconde place
|
||||
if self.code_valide and self.code_valide != self.codes[0]:
|
||||
code_default = self.codes[0]
|
||||
if self.code_valide in self.codes:
|
||||
self.codes.remove(self.code_valide)
|
||||
if sco_codes.BUT_CODES_ORDERED.get(
|
||||
self.code_valide, 0
|
||||
) > sco_codes.BUT_CODES_ORDERED.get(code_default, 0):
|
||||
self.codes.insert(0, self.code_valide)
|
||||
else:
|
||||
self.codes.insert(1, self.code_valide)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"""<{self.__class__.__name__} rcue={self.rcue} valid={self.code_valide
|
||||
} codes={self.codes} explanation={self.explanation}"""
|
||||
|
||||
def record(self, code: str, no_overwrite=False):
|
||||
"""Enregistre le code"""
|
||||
"""Enregistre le code RCUE.
|
||||
Note:
|
||||
- si le RCUE est ADJ, les UE non validées sont passées à ADJ
|
||||
XXX on pourra imposer ici d'autres règles de cohérence
|
||||
"""
|
||||
if self.rcue is None:
|
||||
return # pas de RCUE a enregistrer
|
||||
if self.inscription_etat != scu.INSCRIT:
|
||||
@ -921,13 +1021,10 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
||||
parcours_id = self.parcour.id if self.parcour is not None else None
|
||||
if self.validation:
|
||||
db.session.delete(self.validation)
|
||||
db.session.flush()
|
||||
db.session.commit()
|
||||
if code is None:
|
||||
self.validation = None
|
||||
else:
|
||||
# log(
|
||||
# f"RCUE.record(etudid={self.etud.id}, ue1_id={self.rcue.ue_1.id}, ue2_id={self.rcue.ue_2.id}, code={code} )"
|
||||
# )
|
||||
self.validation = ApcValidationRCUE(
|
||||
etudid=self.etud.id,
|
||||
formsemestre_id=self.rcue.formsemestre_2.id,
|
||||
@ -936,12 +1033,25 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
||||
parcours_id=parcours_id,
|
||||
code=code,
|
||||
)
|
||||
db.session.add(self.validation)
|
||||
db.session.commit()
|
||||
Scolog.logdb(
|
||||
method="jury_but",
|
||||
etudid=self.etud.id,
|
||||
msg=f"Validation {self.rcue}: {code}",
|
||||
commit=True,
|
||||
)
|
||||
db.session.add(self.validation)
|
||||
log(f"rcue.record {self}: {code}")
|
||||
|
||||
# Modifie au besoin les codes d'UE
|
||||
if code == "ADJ":
|
||||
deca = self.deca
|
||||
for ue_id in (self.rcue.ue_1.id, self.rcue.ue_2.id):
|
||||
dec_ue = deca.decisions_ues.get(ue_id)
|
||||
if dec_ue and dec_ue.code_valide not in CODES_UE_VALIDES:
|
||||
log(f"rcue.record: force ADJ sur {dec_ue}")
|
||||
dec_ue.record("ADJ")
|
||||
|
||||
if self.rcue.formsemestre_1 is not None:
|
||||
sco_cache.invalidate_formsemestre(
|
||||
formsemestre_id=self.rcue.formsemestre_1.id
|
||||
@ -950,6 +1060,7 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
||||
sco_cache.invalidate_formsemestre(
|
||||
formsemestre_id=self.rcue.formsemestre_2.id
|
||||
)
|
||||
self.code_valide = code # mise à jour état
|
||||
self.recorded = True
|
||||
|
||||
def erase(self):
|
||||
@ -957,6 +1068,7 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
||||
# par prudence, on requete toutes les validations, en cas de doublons
|
||||
validations = self.rcue.query_validations()
|
||||
for validation in validations:
|
||||
log(f"DecisionsProposeesRCUE: deleting {validation}")
|
||||
db.session.delete(validation)
|
||||
db.session.flush()
|
||||
|
||||
@ -1010,14 +1122,14 @@ class DecisionsProposeesUE(DecisionsProposees):
|
||||
):
|
||||
# Une UE peut être validée plusieurs fois en cas de redoublement (qu'elle soit capitalisée ou non)
|
||||
# mais ici on a restreint au formsemestre donc une seule (prend la première)
|
||||
self.validation = ScolarFormSemestreValidation.query.filter_by(
|
||||
validation = ScolarFormSemestreValidation.query.filter_by(
|
||||
etudid=etud.id, formsemestre_id=formsemestre.id, ue_id=ue.id
|
||||
).first()
|
||||
super().__init__(
|
||||
etud=etud,
|
||||
code_valide=self.validation.code if self.validation is not None else None,
|
||||
code_valide=validation.code if validation is not None else None,
|
||||
)
|
||||
# log(f"built {self}")
|
||||
self.validation = validation
|
||||
self.formsemestre = formsemestre
|
||||
self.ue: UniteEns = ue
|
||||
self.rcue: RegroupementCoherentUE = None
|
||||
@ -1056,11 +1168,11 @@ class DecisionsProposeesUE(DecisionsProposees):
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"""<{self.__class__.__name__} ue={self.ue.acronyme} valid={self.code_valide
|
||||
} codes={self.codes} explanation={self.explanation}"""
|
||||
} codes={self.codes} explanation={self.explanation}>"""
|
||||
|
||||
def set_rcue(self, rcue: RegroupementCoherentUE):
|
||||
"""Rattache cette UE à un RCUE. Cela peut modifier les codes
|
||||
proposés (si compensation)"""
|
||||
proposés par compute_codes() (si compensation)"""
|
||||
self.rcue = rcue
|
||||
|
||||
def compute_codes(self):
|
||||
@ -1098,6 +1210,7 @@ class DecisionsProposeesUE(DecisionsProposees):
|
||||
method="jury_but",
|
||||
etudid=self.etud.id,
|
||||
msg=f"Validation UE {self.ue.id} {self.ue.acronyme}: effacée",
|
||||
commit=True,
|
||||
)
|
||||
else:
|
||||
self.validation = ScolarFormSemestreValidation(
|
||||
@ -1107,15 +1220,18 @@ class DecisionsProposeesUE(DecisionsProposees):
|
||||
code=code,
|
||||
moy_ue=self.moy_ue,
|
||||
)
|
||||
db.session.add(self.validation)
|
||||
db.session.commit()
|
||||
Scolog.logdb(
|
||||
method="jury_but",
|
||||
etudid=self.etud.id,
|
||||
msg=f"Validation UE {self.ue.id} {self.ue.acronyme}({self.moy_ue}): {code}",
|
||||
commit=True,
|
||||
)
|
||||
db.session.add(self.validation)
|
||||
log(f"DecisionsProposeesUE: recording {self.validation}")
|
||||
|
||||
sco_cache.invalidate_formsemestre(formsemestre_id=self.formsemestre.id)
|
||||
self.code_valide = code # mise à jour
|
||||
self.recorded = True
|
||||
|
||||
def erase(self):
|
||||
@ -1126,13 +1242,14 @@ class DecisionsProposeesUE(DecisionsProposees):
|
||||
)
|
||||
for validation in validations:
|
||||
log(f"DecisionsProposeesUE: deleting {validation}")
|
||||
db.session.delete(validation)
|
||||
Scolog.logdb(
|
||||
method="jury_but",
|
||||
etudid=self.etud.id,
|
||||
msg=f"Validation UE {validation.ue.id} {validation.ue.acronyme}: effacée",
|
||||
)
|
||||
db.session.delete(validation)
|
||||
db.session.flush()
|
||||
|
||||
db.session.commit()
|
||||
|
||||
def descr_validation(self) -> str:
|
||||
"""Description validation niveau enregistrée, pour PV jury.
|
||||
@ -1148,7 +1265,7 @@ class BUTCursusEtud: # WIP TODO
|
||||
|
||||
def __init__(self, formsemestre: FormSemestre, etud: Identite):
|
||||
if formsemestre.formation.referentiel_competence is None:
|
||||
raise ScoException("BUTCursusEtud: pas de référentiel de compétences")
|
||||
raise ScoNoReferentielCompetences(formation=formsemestre.formation)
|
||||
assert len(etud.formsemestre_inscriptions) > 0
|
||||
self.formsemestre = formsemestre
|
||||
self.etud = etud
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
@ -32,7 +32,7 @@ from app.scodoc.sco_codes_parcours import (
|
||||
from app.scodoc import sco_formsemestre_status
|
||||
from app.scodoc import sco_pvjury
|
||||
from app.scodoc import sco_utils as scu
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences
|
||||
|
||||
|
||||
def formsemestre_saisie_jury_but(
|
||||
@ -63,14 +63,7 @@ def formsemestre_saisie_jury_but(
|
||||
# raise ScoValueError("Cette page ne fonctionne que sur les semestres pairs")
|
||||
|
||||
if formsemestre2.formation.referentiel_competence is None:
|
||||
raise ScoValueError(
|
||||
"""
|
||||
<p>Pas de référentiel de compétences associé à la formation !</p>
|
||||
<p>Pour associer un référentiel, passer par le menu <b>Semestre /
|
||||
Voir la formation... </b> et suivre le lien <em>"associer à un référentiel
|
||||
de compétences"</em>
|
||||
"""
|
||||
)
|
||||
raise ScoNoReferentielCompetences(formation=formsemestre2.formation)
|
||||
|
||||
rows, titles, column_ids, jury_stats = get_jury_but_table(
|
||||
formsemestre2, read_only=read_only, mode=mode
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
@ -15,12 +15,19 @@ from app.scodoc import sco_cache
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
def formsemestre_validation_auto_but(formsemestre: FormSemestre, only_adm=True) -> int:
|
||||
def formsemestre_validation_auto_but(
|
||||
formsemestre: FormSemestre, only_adm: bool = True, no_overwrite: bool = True
|
||||
) -> int:
|
||||
"""Calcul automatique des décisions de jury sur une année BUT.
|
||||
Ne modifie jamais de décisions de l'année scolaire précédente, même
|
||||
si on a des RCUE "à cheval".
|
||||
Normalement, only_adm est True et on n'enregistre que les décisions ADM (de droit).
|
||||
Si only_adm est faux, on enregistre la première décision proposée par ScoDoc
|
||||
(mode à n'utiliser que pour les tests)
|
||||
|
||||
Si no_overwrite est vrai (défaut), ne ré-écrit jamais les codes déjà enregistrés
|
||||
(utiliser faux pour certains tests)
|
||||
|
||||
Returns: nombre d'étudiants "admis"
|
||||
"""
|
||||
if not formsemestre.formation.is_apc():
|
||||
@ -33,7 +40,7 @@ def formsemestre_validation_auto_but(formsemestre: FormSemestre, only_adm=True)
|
||||
if deca.admis: # année réussie
|
||||
nb_admis += 1
|
||||
if deca.admis or not only_adm:
|
||||
deca.record_all()
|
||||
deca.record_all(no_overwrite=no_overwrite)
|
||||
|
||||
db.session.commit()
|
||||
return nb_admis
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
@ -30,6 +30,7 @@ from app.models import (
|
||||
Identite,
|
||||
UniteEns,
|
||||
ScolarAutorisationInscription,
|
||||
ScolarFormSemestreValidation,
|
||||
)
|
||||
from app.scodoc import html_sco_header
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
@ -41,32 +42,21 @@ def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
|
||||
Si pas read_only, menus sélection codes jury.
|
||||
"""
|
||||
H = []
|
||||
if deca.code_valide and not read_only:
|
||||
erase_span = f"""<a href="{
|
||||
url_for("notes.formsemestre_jury_but_erase",
|
||||
scodoc_dept=g.scodoc_dept, formsemestre_id=deca.formsemestre_id,
|
||||
etudid=deca.etud.id)}" class="stdlink">effacer décisions</a>"""
|
||||
else:
|
||||
erase_span = ""
|
||||
|
||||
H.append("""<div class="but_section_annee">""")
|
||||
if deca.jury_annuel:
|
||||
H.append(
|
||||
f"""
|
||||
<div>
|
||||
<b>Décision de jury pour l'année :</b> {
|
||||
_gen_but_select("code_annee", deca.codes, deca.code_valide,
|
||||
disabled=True, klass="manual")
|
||||
}
|
||||
<span>({'non ' if deca.code_valide is None else ''}enregistrée)</span>
|
||||
<span>{erase_span}</span>
|
||||
</div>
|
||||
H.append(
|
||||
f"""
|
||||
<div>
|
||||
<b>Décision de jury pour l'année :</b> {
|
||||
_gen_but_select("code_annee", deca.codes, deca.code_valide,
|
||||
disabled=True, klass="manual")
|
||||
}
|
||||
<span>({deca.code_valide or 'non'} enregistrée)</span>
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
div_explanation = f"""<div class="but_explanation">{deca.explanation}</div>"""
|
||||
else:
|
||||
H.append("""<div><em>Pas de décision annuelle (sem. impair).</em></div>""")
|
||||
div_explanation = ""
|
||||
)
|
||||
div_explanation = f"""<div class="but_explanation">{deca.explanation}</div>"""
|
||||
|
||||
H.append("""</div>""")
|
||||
|
||||
formsemestre_1 = deca.formsemestre_impair
|
||||
@ -119,8 +109,8 @@ def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
|
||||
if ue.niveau_competence and ue.niveau_competence.id == niveau.id
|
||||
]
|
||||
ue_pair = ues[0] if ues else None
|
||||
# Les UEs à afficher, toujours en readonly
|
||||
# sur le formsemestre de l'année précédente du redoublant
|
||||
# Les UEs à afficher,
|
||||
# qui seront toujours en readonly sur le formsemestre de l'année précédente du redoublant
|
||||
ues_ro = [
|
||||
(
|
||||
ue_impair,
|
||||
@ -143,6 +133,7 @@ def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
|
||||
deca.decisions_ues[ue.id],
|
||||
disabled=read_only or ue_read_only,
|
||||
annee_prec=ue_read_only,
|
||||
niveau_id=ue.niveau_competence.id,
|
||||
)
|
||||
)
|
||||
else:
|
||||
@ -161,6 +152,7 @@ def _gen_but_select(
|
||||
code_valide: str,
|
||||
disabled: bool = False,
|
||||
klass: str = "",
|
||||
data: dict = {},
|
||||
) -> str:
|
||||
"Le menu html select avec les codes"
|
||||
# if disabled: # mauvaise idée car le disabled est traité en JS
|
||||
@ -176,8 +168,11 @@ def _gen_but_select(
|
||||
)
|
||||
return f"""<select required name="{name}"
|
||||
class="but_code {klass}"
|
||||
data-orig_code="{code_valide or (codes[0] if codes else '')}"
|
||||
data-orig_recorded="{code_valide or ''}"
|
||||
onchange="change_menu_code(this);"
|
||||
{"disabled" if disabled else ""}
|
||||
{" ".join( f'data-{k}="{v}"' for (k,v) in data.items() )}
|
||||
>{options_htm}</select>
|
||||
"""
|
||||
|
||||
@ -187,6 +182,7 @@ def _gen_but_niveau_ue(
|
||||
dec_ue: DecisionsProposeesUE,
|
||||
disabled: bool = False,
|
||||
annee_prec: bool = False,
|
||||
niveau_id: int = None,
|
||||
) -> str:
|
||||
if dec_ue.ue_status and dec_ue.ue_status["is_capitalized"]:
|
||||
moy_ue_str = f"""<span class="ue_cap">{
|
||||
@ -207,7 +203,14 @@ def _gen_but_niveau_ue(
|
||||
"""
|
||||
else:
|
||||
moy_ue_str = f"""<span>{scu.fmt_note(dec_ue.moy_ue)}</span>"""
|
||||
scoplement = ""
|
||||
if dec_ue.code_valide:
|
||||
scoplement = f"""<div class="scoplement">
|
||||
Code {dec_ue.code_valide} enregistré le {dec_ue.validation.event_date.strftime("%d/%m/%Y")}
|
||||
à {dec_ue.validation.event_date.strftime("%Hh%M")}
|
||||
</div>
|
||||
"""
|
||||
else:
|
||||
scoplement = ""
|
||||
|
||||
return f"""<div class="but_niveau_ue {
|
||||
'recorded' if dec_ue.code_valide is not None else ''}
|
||||
@ -221,7 +224,9 @@ def _gen_but_niveau_ue(
|
||||
<div class="but_code">{
|
||||
_gen_but_select("code_ue_"+str(ue.id),
|
||||
dec_ue.codes,
|
||||
dec_ue.code_valide, disabled=disabled
|
||||
dec_ue.code_valide,
|
||||
disabled=disabled,
|
||||
klass=f"code_ue ue_rcue_{niveau_id}" if not disabled else ""
|
||||
)
|
||||
}</div>
|
||||
|
||||
@ -245,21 +250,29 @@ def _gen_but_rcue(dec_rcue: DecisionsProposeesRCUE, niveau: ApcNiveau) -> str:
|
||||
else ""
|
||||
)
|
||||
|
||||
# Déjà enregistré ?
|
||||
niveau_rcue_class = ""
|
||||
if dec_rcue.code_valide is not None and dec_rcue.codes:
|
||||
if dec_rcue.code_valide == dec_rcue.codes[0]:
|
||||
niveau_rcue_class = "recorded"
|
||||
else:
|
||||
niveau_rcue_class = "recorded_different"
|
||||
|
||||
return f"""
|
||||
<div class="but_niveau_rcue
|
||||
{'recorded' if dec_rcue.code_valide is not None else ''}
|
||||
<div class="but_niveau_rcue {niveau_rcue_class}
|
||||
">
|
||||
<div class="but_note with_scoplement">
|
||||
<div>{scu.fmt_note(dec_rcue.rcue.moy_rcue)}</div>
|
||||
{scoplement}
|
||||
</div>
|
||||
<div class="but_code">
|
||||
<div>{_gen_but_select("code_rcue_"+str(niveau.id),
|
||||
{_gen_but_select("code_rcue_"+str(niveau.id),
|
||||
dec_rcue.codes,
|
||||
dec_rcue.code_valide,
|
||||
disabled=True, klass="manual"
|
||||
disabled=True,
|
||||
klass="manual code_rcue",
|
||||
data = { "niveau_id" : str(niveau.id)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
@ -278,17 +291,15 @@ def jury_but_semestriel(
|
||||
semestre_terminal = (
|
||||
formsemestre.semestre_id >= formsemestre.formation.get_parcours().NB_SEM
|
||||
)
|
||||
autorisations_passage = ScolarAutorisationInscription.query.filter_by(
|
||||
etudid=etud.id,
|
||||
origin_formsemestre_id=formsemestre.id,
|
||||
).all()
|
||||
# Par défaut: autorisé à passer dans le semestre suivant si sem. impair,
|
||||
# ou si décision déjà enregistrée:
|
||||
est_autorise_a_passer = (formsemestre.semestre_id % 2) or (
|
||||
formsemestre.semestre_id + 1
|
||||
) in (
|
||||
a.semestre_id
|
||||
for a in ScolarAutorisationInscription.query.filter_by(
|
||||
etudid=etud.id,
|
||||
origin_formsemestre_id=formsemestre.id,
|
||||
)
|
||||
)
|
||||
) in (a.semestre_id for a in autorisations_passage)
|
||||
decisions_ues = {
|
||||
ue.id: DecisionsProposeesUE(etud, formsemestre, ue, inscription_etat)
|
||||
for ue in ues
|
||||
@ -312,7 +323,9 @@ def jury_but_semestriel(
|
||||
flash("codes enregistrés")
|
||||
if not semestre_terminal:
|
||||
if request.form.get("autorisation_passage"):
|
||||
if not est_autorise_a_passer:
|
||||
if not formsemestre.semestre_id + 1 in (
|
||||
a.semestre_id for a in autorisations_passage
|
||||
):
|
||||
ScolarAutorisationInscription.autorise_etud(
|
||||
etud.id,
|
||||
formsemestre.formation.formation_code,
|
||||
@ -351,7 +364,7 @@ def jury_but_semestriel(
|
||||
warning = ""
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
page_title="Validation BUT",
|
||||
page_title=f"Validation BUT S{formsemestre.semestre_id}",
|
||||
formsemestre_id=formsemestre.id,
|
||||
etudid=etud.id,
|
||||
cssstyles=("css/jury_but.css",),
|
||||
@ -372,25 +385,35 @@ def jury_but_semestriel(
|
||||
}">{etud.photo_html(title="fiche de " + etud.nomprenom)}</a>
|
||||
</div>
|
||||
</div>
|
||||
<h3>Jury sur un semestre BUT isolé</h3>
|
||||
<h3>Jury sur un semestre BUT isolé (ne concerne que les UEs)</h3>
|
||||
{warning}
|
||||
</div>
|
||||
|
||||
<form method="POST">
|
||||
<form method="post" id="jury_but">
|
||||
""",
|
||||
]
|
||||
if (not read_only) and any([dec.code_valide for dec in decisions_ues.values()]):
|
||||
erase_span = f"""<a href="{
|
||||
url_for("notes.formsemestre_jury_but_erase",
|
||||
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id,
|
||||
etudid=etud.id, only_one_sem=1)}" class="stdlink">effacer les décisions enregistrées</a>"""
|
||||
else:
|
||||
erase_span = "Cet étudiant n'a aucune décision enregistrée pour ce semestre."
|
||||
|
||||
erase_span = ""
|
||||
if not read_only:
|
||||
# Requête toutes les validations (pas seulement celles du deca courant),
|
||||
# au cas où: changement d'architecture, saisie en mode classique, ...
|
||||
validations = ScolarFormSemestreValidation.query.filter_by(
|
||||
etudid=etud.id, formsemestre_id=formsemestre.id
|
||||
).all()
|
||||
if validations:
|
||||
erase_span = f"""<a href="{
|
||||
url_for("notes.formsemestre_jury_but_erase",
|
||||
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id,
|
||||
etudid=etud.id, only_one_sem=1)
|
||||
}" class="stdlink">effacer les décisions enregistrées</a>"""
|
||||
else:
|
||||
erase_span = (
|
||||
"Cet étudiant n'a aucune décision enregistrée pour ce semestre."
|
||||
)
|
||||
|
||||
H.append(
|
||||
f"""
|
||||
<div class="but_section_annee">
|
||||
<span>{erase_span}</span>
|
||||
</div>
|
||||
<div><b>Unités d'enseignement de S{formsemestre.semestre_id}:</b></div>
|
||||
"""
|
||||
@ -440,6 +463,9 @@ def jury_but_semestriel(
|
||||
<input type="checkbox" name="autorisation_passage" value="1" {
|
||||
"checked" if est_autorise_a_passer else ""}>
|
||||
<em>autoriser à passer dans le semestre S{formsemestre.semestre_id+1}</em>
|
||||
{("(autorisations enregistrées: " + ' '.join(
|
||||
'S' + str(a.semestre_id or '') for a in autorisations_passage) + ")"
|
||||
) if autorisations_passage else ""}
|
||||
</input>
|
||||
</div>
|
||||
"""
|
||||
@ -447,9 +473,10 @@ def jury_but_semestriel(
|
||||
else:
|
||||
H.append("""<div class="help">dernier semestre de la formation.</div>""")
|
||||
H.append(
|
||||
"""
|
||||
f"""
|
||||
<div class="but_buttons">
|
||||
<input type="submit" value="Enregistrer ces décisions">
|
||||
<span><input type="submit" value="Enregistrer ces décisions"></span>
|
||||
<span>{erase_span}</span>
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: UTF-8 -*
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# ScoDoc
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# ScoDoc
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# ScoDoc
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# ScoDoc
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -1,6 +1,6 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
"""ScoDoc 9 models : Référentiel Compétence BUT 2021
|
||||
@ -14,7 +14,7 @@ import sqlalchemy
|
||||
from app import db
|
||||
|
||||
from app.scodoc.sco_utils import ModuleType
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences
|
||||
|
||||
|
||||
# from https://stackoverflow.com/questions/2537471/method-of-iterating-over-sqlalchemy-models-defined-columns
|
||||
@ -54,13 +54,15 @@ class ApcReferentielCompetences(db.Model, XMLModel):
|
||||
"Référentiel de compétence d'une spécialité"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
|
||||
annexe = db.Column(db.Text())
|
||||
specialite = db.Column(db.Text())
|
||||
specialite_long = db.Column(db.Text())
|
||||
type_titre = db.Column(db.Text())
|
||||
type_structure = db.Column(db.Text())
|
||||
annexe = db.Column(db.Text()) # '1', '22', ...
|
||||
specialite = db.Column(db.Text()) # 'CJ', 'RT', 'INFO', ...
|
||||
specialite_long = db.Column(
|
||||
db.Text()
|
||||
) # 'Carrière Juridique', 'Réseaux et télécommunications', ...
|
||||
type_titre = db.Column(db.Text()) # 'B.U.T.'
|
||||
type_structure = db.Column(db.Text()) # 'type1', 'type2', ...
|
||||
type_departement = db.Column(db.Text()) # "secondaire", "tertiaire"
|
||||
version_orebut = db.Column(db.Text())
|
||||
version_orebut = db.Column(db.Text()) # '2021-12-11 00:00:00'
|
||||
_xml_attribs = { # Orébut xml attrib : attribute
|
||||
"type": "type_titre",
|
||||
"version": "version_orebut",
|
||||
@ -322,9 +324,8 @@ class ApcNiveau(db.Model, XMLModel):
|
||||
if annee not in {1, 2, 3}:
|
||||
raise ValueError("annee invalide pour un parcours BUT")
|
||||
if referentiel_competence is None:
|
||||
raise ScoValueError(
|
||||
"Pas de référentiel de compétences associé à la formation !"
|
||||
)
|
||||
raise ScoNoReferentielCompetences()
|
||||
|
||||
annee_formation = f"BUT{annee}"
|
||||
if parcour is None:
|
||||
return ApcNiveau.query.filter(
|
||||
|
@ -68,7 +68,8 @@ class ApcValidationRCUE(db.Model):
|
||||
"description en HTML"
|
||||
return f"""Décision sur RCUE {self.ue1.acronyme}/{self.ue2.acronyme}:
|
||||
<b>{self.code}</b>
|
||||
<em>enregistrée le {self.date.strftime("%d/%m/%Y")}</em>"""
|
||||
<em>enregistrée le {self.date.strftime("%d/%m/%Y")}
|
||||
à {self.date.strftime("%Hh%M")}</em>"""
|
||||
|
||||
def niveau(self) -> ApcNiveau:
|
||||
"""Le niveau de compétence associé à cet RCUE."""
|
||||
@ -180,8 +181,9 @@ class RegroupementCoherentUE:
|
||||
return self.query_validations().count() > 0
|
||||
|
||||
def est_compensable(self):
|
||||
"""Vrai si ce RCUE est validable par compensation
|
||||
c'est à dire que sa moyenne est > 10 avec une UE < 10
|
||||
"""Vrai si ce RCUE est validable (uniquement) par compensation
|
||||
c'est à dire que sa moyenne est > 10 avec une UE < 10.
|
||||
Note: si ADM, est_compensable est faux.
|
||||
"""
|
||||
return (
|
||||
(self.moy_rcue is not None)
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: UTF-8 -*
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
@ -56,9 +56,9 @@ class FormSemestre(db.Model):
|
||||
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
|
||||
formation_id = db.Column(db.Integer, db.ForeignKey("notes_formations.id"))
|
||||
semestre_id = db.Column(db.Integer, nullable=False, default=1, server_default="1")
|
||||
titre = db.Column(db.Text())
|
||||
date_debut = db.Column(db.Date())
|
||||
date_fin = db.Column(db.Date())
|
||||
titre = db.Column(db.Text(), nullable=False)
|
||||
date_debut = db.Column(db.Date(), nullable=False)
|
||||
date_fin = db.Column(db.Date(), nullable=False)
|
||||
etat = db.Column(
|
||||
db.Boolean(), nullable=False, default=True, server_default="true"
|
||||
) # False si verrouillé
|
||||
@ -87,7 +87,10 @@ class FormSemestre(db.Model):
|
||||
)
|
||||
# couleur fond bulletins HTML:
|
||||
bul_bgcolor = db.Column(
|
||||
db.String(SHORT_STR_LEN), default="white", server_default="white"
|
||||
db.String(SHORT_STR_LEN),
|
||||
default="white",
|
||||
server_default="white",
|
||||
nullable=False,
|
||||
)
|
||||
# autorise resp. a modifier semestre:
|
||||
resp_can_edit = db.Column(
|
||||
@ -114,6 +117,7 @@ class FormSemestre(db.Model):
|
||||
"ModuleImpl",
|
||||
backref="formsemestre",
|
||||
lazy="dynamic",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
etuds = db.relationship(
|
||||
"Identite",
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: UTF-8 -*
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
|
@ -20,14 +20,12 @@ class ModuleImpl(db.Model):
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
moduleimpl_id = db.synonym("id")
|
||||
module_id = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey("notes_modules.id"),
|
||||
)
|
||||
module_id = db.Column(db.Integer, db.ForeignKey("notes_modules.id"), nullable=False)
|
||||
formsemestre_id = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey("notes_formsemestre.id"),
|
||||
index=True,
|
||||
nullable=False,
|
||||
)
|
||||
responsable_id = db.Column("responsable_id", db.Integer, db.ForeignKey("user.id"))
|
||||
# formule de calcul moyenne:
|
||||
|
@ -37,7 +37,9 @@ class Module(db.Model):
|
||||
# Type: ModuleType.STANDARD, MALUS, RESSOURCE, SAE (enum)
|
||||
module_type = db.Column(db.Integer, nullable=False, default=0, server_default="0")
|
||||
# Relations:
|
||||
modimpls = db.relationship("ModuleImpl", backref="module", lazy="dynamic")
|
||||
modimpls = db.relationship(
|
||||
"ModuleImpl", backref="module", lazy="dynamic", cascade="all, delete-orphan"
|
||||
)
|
||||
ues_apc = db.relationship("UniteEns", secondary="module_ue_coef", viewonly=True)
|
||||
tags = db.relationship(
|
||||
"NotesTag",
|
||||
|
@ -4,6 +4,7 @@
|
||||
"""
|
||||
|
||||
from app import db
|
||||
from app import log
|
||||
from app.models import SHORT_STR_LEN
|
||||
from app.models import CODE_STR_LEN
|
||||
from app.models.events import Scolog
|
||||
@ -93,6 +94,10 @@ class ScolarAutorisationInscription(db.Model):
|
||||
db.ForeignKey("notes_formsemestre.id"),
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"""{self.__class__.__name__}(id={self.id}, etudid={
|
||||
self.etudid}, semestre_id={self.semestre_id})"""
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"as a dict"
|
||||
d = dict(self.__dict__)
|
||||
@ -119,6 +124,7 @@ class ScolarAutorisationInscription(db.Model):
|
||||
Scolog.logdb(
|
||||
"autorise_etud", etudid=etudid, msg=f"Passage vers S{semestre_id}: autorisé"
|
||||
)
|
||||
log(f"ScolarAutorisationInscription: recording {autorisation}")
|
||||
|
||||
@classmethod
|
||||
def delete_autorisation_etud(
|
||||
@ -132,6 +138,7 @@ class ScolarAutorisationInscription(db.Model):
|
||||
)
|
||||
for autorisation in autorisations:
|
||||
db.session.delete(autorisation)
|
||||
log(f"ScolarAutorisationInscription: deleting {autorisation}")
|
||||
Scolog.logdb(
|
||||
"autorise_etud",
|
||||
etudid=etudid,
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
@ -105,13 +105,13 @@ class BaseArchiver(object):
|
||||
try:
|
||||
scu.GSL.acquire()
|
||||
if not os.path.isdir(path):
|
||||
log("creating directory %s" % path)
|
||||
log(f"creating directory {path}")
|
||||
os.mkdir(path)
|
||||
finally:
|
||||
scu.GSL.release()
|
||||
self.initialized = True
|
||||
|
||||
def get_obj_dir(self, oid):
|
||||
def get_obj_dir(self, oid: int):
|
||||
"""
|
||||
:return: path to directory of archives for this object (eg formsemestre_id or etudid).
|
||||
If directory does not yet exist, create it.
|
||||
@ -142,7 +142,7 @@ class BaseArchiver(object):
|
||||
dirs = glob.glob(base + "*")
|
||||
return [os.path.split(x)[1] for x in dirs]
|
||||
|
||||
def list_obj_archives(self, oid):
|
||||
def list_obj_archives(self, oid: int):
|
||||
"""Returns
|
||||
:return: list of archive identifiers for this object (paths to non empty dirs)
|
||||
"""
|
||||
@ -157,7 +157,7 @@ class BaseArchiver(object):
|
||||
dirs.sort()
|
||||
return dirs
|
||||
|
||||
def delete_archive(self, archive_id):
|
||||
def delete_archive(self, archive_id: str):
|
||||
"""Delete (forever) this archive"""
|
||||
self.initialize()
|
||||
try:
|
||||
@ -166,7 +166,7 @@ class BaseArchiver(object):
|
||||
finally:
|
||||
scu.GSL.release()
|
||||
|
||||
def get_archive_date(self, archive_id):
|
||||
def get_archive_date(self, archive_id: str):
|
||||
"""Returns date (as a DateTime object) of an archive"""
|
||||
return datetime.datetime(
|
||||
*[int(x) for x in os.path.split(archive_id)[1].split("-")]
|
||||
@ -183,17 +183,17 @@ class BaseArchiver(object):
|
||||
files.sort()
|
||||
return [f for f in files if f and f[0] != "_"]
|
||||
|
||||
def get_archive_name(self, archive_id):
|
||||
def get_archive_name(self, archive_id: str):
|
||||
"""name identifying archive, to be used in web URLs"""
|
||||
return os.path.split(archive_id)[1]
|
||||
|
||||
def is_valid_archive_name(self, archive_name):
|
||||
def is_valid_archive_name(self, archive_name: str):
|
||||
"""check if name is valid."""
|
||||
return re.match(
|
||||
"^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}$", archive_name
|
||||
)
|
||||
|
||||
def get_id_from_name(self, oid, archive_name):
|
||||
def get_id_from_name(self, oid, archive_name: str):
|
||||
"""returns archive id (check that name is valid)"""
|
||||
self.initialize()
|
||||
if not self.is_valid_archive_name(archive_name):
|
||||
@ -206,7 +206,7 @@ class BaseArchiver(object):
|
||||
raise ScoValueError(f"Archive {archive_name} introuvable")
|
||||
return archive_id
|
||||
|
||||
def get_archive_description(self, archive_id):
|
||||
def get_archive_description(self, archive_id: str) -> str:
|
||||
"""Return description of archive"""
|
||||
self.initialize()
|
||||
filename = os.path.join(archive_id, "_description.txt")
|
||||
@ -247,7 +247,7 @@ class BaseArchiver(object):
|
||||
data = data.encode(scu.SCO_ENCODING)
|
||||
self.initialize()
|
||||
filename = scu.sanitize_filename(filename)
|
||||
log("storing %s (%d bytes) in %s" % (filename, len(data), archive_id))
|
||||
log(f"storing {filename} ({len(data)} bytes) in {archive_id}")
|
||||
try:
|
||||
scu.GSL.acquire()
|
||||
fname = os.path.join(archive_id, filename)
|
||||
@ -261,16 +261,18 @@ class BaseArchiver(object):
|
||||
"""Retreive data"""
|
||||
self.initialize()
|
||||
if not scu.is_valid_filename(filename):
|
||||
log('Archiver.get: invalid filename "%s"' % filename)
|
||||
log(f"""Archiver.get: invalid filename '{filename}'""")
|
||||
raise ScoValueError("archive introuvable (déjà supprimée ?)")
|
||||
fname = os.path.join(archive_id, filename)
|
||||
log("reading archive file %s" % fname)
|
||||
log(f"reading archive file {fname}")
|
||||
with open(fname, "rb") as f:
|
||||
data = f.read()
|
||||
return data
|
||||
|
||||
def get_archived_file(self, oid, archive_name, filename):
|
||||
"""Recupere donnees du fichier indiqué et envoie au client"""
|
||||
"""Recupère les donnees du fichier indiqué et envoie au client.
|
||||
Returns: Response
|
||||
"""
|
||||
archive_id = self.get_id_from_name(oid, archive_name)
|
||||
data = self.get(archive_id, filename)
|
||||
mime = mimetypes.guess_type(filename)[0]
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
@ -435,7 +435,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
||||
plusminus = pluslink
|
||||
try:
|
||||
ects_txt = str(int(ue["ects"]))
|
||||
except (ValueError, KeyError):
|
||||
except (ValueError, KeyError, TypeError):
|
||||
ects_txt = "-"
|
||||
|
||||
t = {
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
@ -205,6 +205,20 @@ BUT_CODES_PASSAGE = {
|
||||
PAS1NCI,
|
||||
ATJ,
|
||||
}
|
||||
# les codes, du plus "défavorable" à l'étudiant au plus favorable:
|
||||
# (valeur par défaut 0)
|
||||
BUT_CODES_ORDERED = {
|
||||
"NAR": 0,
|
||||
"DEF": 0,
|
||||
"AJ": 10,
|
||||
"ATJ": 20,
|
||||
"CMP": 50,
|
||||
"ADC": 50,
|
||||
"PASD": 50,
|
||||
"PAS1NCI": 60,
|
||||
"ADJ": 100,
|
||||
"ADM": 100,
|
||||
}
|
||||
|
||||
|
||||
def code_semestre_validant(code: str) -> bool:
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# ScoDoc
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -4,7 +4,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# ScoDoc
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# Copyright (c) 1999 - 2023 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
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user