PV jury annuel BUT
This commit is contained in:
parent
372a6e6ed6
commit
e8e27dd964
@ -667,6 +667,30 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
db.session.delete(validation)
|
db.session.delete(validation)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
|
|
||||||
|
def get_autorisations_passage(self) -> list[int]:
|
||||||
|
"""Les liste des indices de semestres auxquels on est autorisé à
|
||||||
|
s'inscrire depuis cette année"""
|
||||||
|
formsemestre = self.formsemestre_pair or self.formsemestre_impair
|
||||||
|
if not formsemestre:
|
||||||
|
return []
|
||||||
|
return [
|
||||||
|
a.semestre_id
|
||||||
|
for a in ScolarAutorisationInscription.query.filter_by(
|
||||||
|
etudid=self.etud.id,
|
||||||
|
origin_formsemestre_id=formsemestre.id,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
def descr_niveaux_validation(self, line_sep: str = "\n") -> str:
|
||||||
|
"""Description textuelle des niveaux validés (enregistrés)
|
||||||
|
pour PV jurys
|
||||||
|
"""
|
||||||
|
validations = [
|
||||||
|
dec_rcue.descr_validation()
|
||||||
|
for dec_rcue in self.decisions_rcue_by_niveau.values()
|
||||||
|
]
|
||||||
|
return line_sep.join([v for v in validations if v])
|
||||||
|
|
||||||
|
|
||||||
class DecisionsProposeesRCUE(DecisionsProposees):
|
class DecisionsProposeesRCUE(DecisionsProposees):
|
||||||
"""Liste des codes de décisions que l'on peut proposer pour
|
"""Liste des codes de décisions que l'on peut proposer pour
|
||||||
@ -742,6 +766,21 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
|||||||
db.session.delete(validation)
|
db.session.delete(validation)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
|
|
||||||
|
def descr_validation(self) -> str:
|
||||||
|
"""Description validation niveau enregistrée, pour PV jury.
|
||||||
|
Si le niveau est validé, done son acronyme, sinon chaine vide.
|
||||||
|
"""
|
||||||
|
if self.code_valide in sco_codes.CODES_RCUE_VALIDES:
|
||||||
|
if (
|
||||||
|
self.rcue and self.rcue.ue_1 and self.rcue.ue_1.niveau_competence
|
||||||
|
): # prudence !
|
||||||
|
niveau_titre = self.rcue.ue_1.niveau_competence.competence.titre or ""
|
||||||
|
ordre = self.rcue.ue_1.niveau_competence.ordre
|
||||||
|
else:
|
||||||
|
return "?" # oups ?
|
||||||
|
return f"{niveau_titre} niv. {ordre}"
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
class DecisionsProposeesUE(DecisionsProposees):
|
class DecisionsProposeesUE(DecisionsProposees):
|
||||||
"""Décisions de jury sur une UE du BUT
|
"""Décisions de jury sur une UE du BUT
|
||||||
@ -859,6 +898,14 @@ class DecisionsProposeesUE(DecisionsProposees):
|
|||||||
db.session.delete(validation)
|
db.session.delete(validation)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
|
|
||||||
|
def descr_validation(self) -> str:
|
||||||
|
"""Description validation niveau enregistrée, pour PV jury.
|
||||||
|
Si l'UE est validé, done son acronyme, sinon chaine vide.
|
||||||
|
"""
|
||||||
|
if self.code_valide in sco_codes.CODES_UE_VALIDES:
|
||||||
|
return f"{self.ue.acronyme}"
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
class BUTCursusEtud: # WIP TODO
|
class BUTCursusEtud: # WIP TODO
|
||||||
"""Validation du cursus d'un étudiant"""
|
"""Validation du cursus d'un étudiant"""
|
||||||
|
106
app/but/jury_but_pv.py
Normal file
106
app/but/jury_but_pv.py
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
##############################################################################
|
||||||
|
# ScoDoc
|
||||||
|
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||||
|
# See LICENSE
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""Jury BUT: table synthèse résultats semestre / PV
|
||||||
|
"""
|
||||||
|
from flask import g, request, url_for
|
||||||
|
|
||||||
|
from openpyxl.styles import Font, Border, Side, Alignment, PatternFill
|
||||||
|
|
||||||
|
from app import log
|
||||||
|
from app.but import jury_but
|
||||||
|
from app.models.etudiants import Identite
|
||||||
|
from app.models.formsemestre import FormSemestre
|
||||||
|
from app.scodoc.gen_tables import GenTable
|
||||||
|
from app.scodoc import sco_excel
|
||||||
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
|
from app.scodoc import sco_preferences
|
||||||
|
from app.scodoc import sco_utils as scu
|
||||||
|
|
||||||
|
|
||||||
|
def _descr_cursus_but(etud: Identite) -> str:
|
||||||
|
"description de la liste des semestres BUT suivis"
|
||||||
|
# prend simplement tous les semestre de type APC, ce qui sera faux si
|
||||||
|
# l'étudiant change de spécialité au sein du même département
|
||||||
|
# (ce qui ne peut normalement pas se produire)
|
||||||
|
indices = [
|
||||||
|
ins.formsemestre.semestre_id
|
||||||
|
for ins in etud.formsemestre_inscriptions
|
||||||
|
if ins.formsemestre.formation.is_apc()
|
||||||
|
]
|
||||||
|
return ", ".join(f"S{indice}" for indice in indices)
|
||||||
|
|
||||||
|
|
||||||
|
def pvjury_table_but(formsemestre_id: int, format="html") -> list[dict]:
|
||||||
|
"""Page récapitulant les décisions de jury BUT
|
||||||
|
formsemestre peut être pair ou impair
|
||||||
|
"""
|
||||||
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
assert formsemestre.formation.is_apc()
|
||||||
|
title = "Jury BUT annuel"
|
||||||
|
|
||||||
|
if format == "html":
|
||||||
|
line_sep = "<br/>"
|
||||||
|
else:
|
||||||
|
line_sep = "\n"
|
||||||
|
# remplace pour le BUT la fonction sco_pvjury.pvjury_table
|
||||||
|
annee_but = (formsemestre.semestre_id + 1) // 2
|
||||||
|
titles = {
|
||||||
|
"nom": "Nom",
|
||||||
|
"cursus": "Cursus",
|
||||||
|
"niveaux": "Niveaux de compétences validés",
|
||||||
|
"decision_but": f"Décision BUT{annee_but}",
|
||||||
|
"diplome": "Résultat au diplôme",
|
||||||
|
"devenir": "Devenir",
|
||||||
|
"observations": "Observations",
|
||||||
|
}
|
||||||
|
rows = []
|
||||||
|
for etudid in formsemestre.etuds_inscriptions:
|
||||||
|
etud: Identite = Identite.query.get(etudid)
|
||||||
|
try:
|
||||||
|
deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
|
||||||
|
if deca.annee_but != annee_but: # wtf ?
|
||||||
|
log(
|
||||||
|
f"pvjury_table_but: inconsistent annee_but {deca.annee_but} != {annee_but}"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
except ScoValueError:
|
||||||
|
deca = None
|
||||||
|
row = {
|
||||||
|
"nom": etud.etat_civil_pv(line_sep=line_sep),
|
||||||
|
"cursus": _descr_cursus_but(etud),
|
||||||
|
"niveaux": deca.descr_niveaux_validation(line_sep=line_sep)
|
||||||
|
if deca
|
||||||
|
else "-",
|
||||||
|
"decision_but": deca.code_valide if deca else "",
|
||||||
|
"devenir": ", ".join([f"S{i}" for i in deca.get_autorisations_passage()]),
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.append(row)
|
||||||
|
|
||||||
|
# Style excel... passages à la ligne sur \n
|
||||||
|
xls_style_base = sco_excel.excel_make_style()
|
||||||
|
xls_style_base["alignment"] = Alignment(wrapText=True, vertical="top")
|
||||||
|
|
||||||
|
tab = GenTable(
|
||||||
|
columns_ids=titles.keys(),
|
||||||
|
rows=rows,
|
||||||
|
titles=titles,
|
||||||
|
origin=f"Généré par {scu.sco_version.SCONAME} le {scu.timedate_human_repr()}",
|
||||||
|
caption=title,
|
||||||
|
html_caption=title,
|
||||||
|
html_class="pvjury_table_but table_leftalign",
|
||||||
|
# html_class_ignore_default=True,
|
||||||
|
html_with_td_classes=True,
|
||||||
|
xls_style_base=xls_style_base,
|
||||||
|
base_url=f"{request.base_url}?formsemestre_id={formsemestre_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=[])
|
@ -98,7 +98,16 @@ def formsemestre_saisie_jury_but(
|
|||||||
]
|
]
|
||||||
if mode == "recap":
|
if mode == "recap":
|
||||||
H.append(
|
H.append(
|
||||||
"""<h3>Décisions de jury enregistrées pour les étudiants de ce semestre</h3>"""
|
f"""<h3>Décisions de jury enregistrées pour les étudiants de ce semestre</h3>
|
||||||
|
<div class="table_jury_but_links">
|
||||||
|
<div>
|
||||||
|
<a href="{url_for(
|
||||||
|
"notes.pvjury_table_but",
|
||||||
|
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre2.id)
|
||||||
|
}" class="stdlink">tableau PV de jury</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
f"""
|
f"""
|
||||||
|
@ -195,7 +195,7 @@ class RegroupementCoherentUE:
|
|||||||
"Si ce RCUE est ADM, CMP ou ADJ, la validation. Sinon, None"
|
"Si ce RCUE est ADM, CMP ou ADJ, la validation. Sinon, None"
|
||||||
validation = self.query_validations().first()
|
validation = self.query_validations().first()
|
||||||
if (validation is not None) and (
|
if (validation is not None) and (
|
||||||
validation.code in {sco_codes.ADM, sco_codes.ADJ, sco_codes.CMP}
|
validation.code in sco_codes.CODES_RCUE_VALIDES
|
||||||
):
|
):
|
||||||
return validation
|
return validation
|
||||||
return None
|
return None
|
||||||
|
@ -365,6 +365,15 @@ class Identite(db.Model):
|
|||||||
|
|
||||||
return situation
|
return situation
|
||||||
|
|
||||||
|
def etat_civil_pv(self, line_sep="\n") -> str:
|
||||||
|
"""Présentation, pour PV jury
|
||||||
|
M. Pierre Dupont
|
||||||
|
n° 12345678
|
||||||
|
né(e) le 7/06/1974
|
||||||
|
à Paris
|
||||||
|
"""
|
||||||
|
return f"""{self.nomprenom}{line_sep}n°{self.code_nip or ""}{line_sep}né{self.e} le {self.date_naissance.strftime("%d/%m/%Y") if self.date_naissance else ""}{line_sep}à {self.lieu_naissance or ""}"""
|
||||||
|
|
||||||
def photo_html(self, title=None, size="small") -> str:
|
def photo_html(self, title=None, size="small") -> str:
|
||||||
"""HTML img tag for the photo, either in small size (h90)
|
"""HTML img tag for the photo, either in small size (h90)
|
||||||
or original size (size=="orig")
|
or original size (size=="orig")
|
||||||
|
@ -127,6 +127,7 @@ class GenTable(object):
|
|||||||
filename="table", # filename, without extension
|
filename="table", # filename, without extension
|
||||||
xls_sheet_name="feuille",
|
xls_sheet_name="feuille",
|
||||||
xls_before_table=[], # liste de cellules a placer avant la table
|
xls_before_table=[], # liste de cellules a placer avant la table
|
||||||
|
xls_style_base=None, # style excel pour les cellules
|
||||||
pdf_title="", # au dessus du tableau en pdf
|
pdf_title="", # au dessus du tableau en pdf
|
||||||
pdf_table_style=None,
|
pdf_table_style=None,
|
||||||
pdf_col_widths=None,
|
pdf_col_widths=None,
|
||||||
@ -151,6 +152,7 @@ class GenTable(object):
|
|||||||
self.page_title = page_title
|
self.page_title = page_title
|
||||||
self.pdf_link = pdf_link
|
self.pdf_link = pdf_link
|
||||||
self.xls_link = xls_link
|
self.xls_link = xls_link
|
||||||
|
self.xls_style_base = xls_style_base
|
||||||
self.xml_link = xml_link
|
self.xml_link = xml_link
|
||||||
# HTML parameters:
|
# HTML parameters:
|
||||||
if not table_id: # random id
|
if not table_id: # random id
|
||||||
@ -495,7 +497,8 @@ class GenTable(object):
|
|||||||
sheet = wb.create_sheet(sheet_name=self.xls_sheet_name)
|
sheet = wb.create_sheet(sheet_name=self.xls_sheet_name)
|
||||||
sheet.rows += self.xls_before_table
|
sheet.rows += self.xls_before_table
|
||||||
style_bold = sco_excel.excel_make_style(bold=True)
|
style_bold = sco_excel.excel_make_style(bold=True)
|
||||||
style_base = sco_excel.excel_make_style()
|
style_base = self.xls_style_base or sco_excel.excel_make_style()
|
||||||
|
|
||||||
sheet.append_row(sheet.make_row(self.get_titles_list(), style_bold))
|
sheet.append_row(sheet.make_row(self.get_titles_list(), style_bold))
|
||||||
for line in self.get_data_list(xls_mode=True):
|
for line in self.get_data_list(xls_mode=True):
|
||||||
sheet.append_row(sheet.make_row(line, style_base))
|
sheet.append_row(sheet.make_row(line, style_base))
|
||||||
|
@ -189,7 +189,7 @@ CODES_SEM_ATTENTES = {ATT: True, ATB: True, ATJ: True} # semestre en attente
|
|||||||
CODES_SEM_REO = {NAR: 1} # reorientation
|
CODES_SEM_REO = {NAR: 1} # reorientation
|
||||||
|
|
||||||
CODES_UE_VALIDES = {ADM: True, CMP: True, ADJ: True} # UE validée
|
CODES_UE_VALIDES = {ADM: True, CMP: True, ADJ: True} # UE validée
|
||||||
|
CODES_RCUE_VALIDES = CODES_UE_VALIDES # Niveau RCUE validé
|
||||||
# Pour le BUT:
|
# Pour le BUT:
|
||||||
CODES_ANNEE_ARRET = {DEF, DEM, ABAN, ABL}
|
CODES_ANNEE_ARRET = {DEF, DEM, ABAN, ABL}
|
||||||
CODES_RCUE = {ADM, AJ, CMP}
|
CODES_RCUE = {ADM, AJ, CMP}
|
||||||
|
@ -59,7 +59,7 @@ class COLORS(Enum):
|
|||||||
LIGHT_YELLOW = "FFFFFF99"
|
LIGHT_YELLOW = "FFFFFF99"
|
||||||
|
|
||||||
|
|
||||||
# Un style est enregistré comme un dictionnaire qui précise la valeur d'un attributdans la liste suivante:
|
# Un style est enregistré comme un dictionnaire qui précise la valeur d'un attribut dans la liste suivante:
|
||||||
# font, border, number_format, fill,...
|
# font, border, number_format, fill,...
|
||||||
# (cf https://openpyxl.readthedocs.io/en/stable/styles.html#working-with-styles)
|
# (cf https://openpyxl.readthedocs.io/en/stable/styles.html#working-with-styles)
|
||||||
|
|
||||||
@ -288,7 +288,7 @@ class ScoExcelSheet:
|
|||||||
value -- contenu de la cellule (texte, numérique, booléen ou date)
|
value -- contenu de la cellule (texte, numérique, booléen ou date)
|
||||||
style -- style par défaut (dictionnaire cf. excel_make_style) de la feuille si non spécifié
|
style -- style par défaut (dictionnaire cf. excel_make_style) de la feuille si non spécifié
|
||||||
"""
|
"""
|
||||||
# adapatation des valeurs si nécessaire
|
# adaptation des valeurs si nécessaire
|
||||||
if value is None:
|
if value is None:
|
||||||
value = ""
|
value = ""
|
||||||
elif value is True:
|
elif value is True:
|
||||||
|
@ -42,6 +42,7 @@ from flask_login import current_user
|
|||||||
|
|
||||||
from app.but import jury_but, jury_but_validation_auto
|
from app.but import jury_but, jury_but_validation_auto
|
||||||
from app.but.forms import jury_but_forms
|
from app.but.forms import jury_but_forms
|
||||||
|
from app.but import jury_but_pv
|
||||||
from app.but import jury_but_view
|
from app.but import jury_but_view
|
||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
from app.comp.res_but import ResultatsSemestreBUT
|
from app.comp.res_but import ResultatsSemestreBUT
|
||||||
@ -2564,6 +2565,8 @@ def formsemestre_validation_suppress_etud(
|
|||||||
# ------------- PV de JURY et archives
|
# ------------- PV de JURY et archives
|
||||||
sco_publish("/formsemestre_pvjury", sco_pvjury.formsemestre_pvjury, Permission.ScoView)
|
sco_publish("/formsemestre_pvjury", sco_pvjury.formsemestre_pvjury, Permission.ScoView)
|
||||||
|
|
||||||
|
sco_publish("/pvjury_table_but", jury_but_pv.pvjury_table_but, Permission.ScoView)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/formsemestre_saisie_jury")
|
@bp.route("/formsemestre_saisie_jury")
|
||||||
@scodoc
|
@scodoc
|
||||||
|
Loading…
Reference in New Issue
Block a user