This commit is contained in:
Jean-Marie Place 2023-06-21 07:37:08 +02:00
parent c0d5eb0f69
commit 6fc3e16bdf
5 changed files with 429 additions and 96 deletions

View File

@ -32,8 +32,10 @@ import time
from flask import flash, abort from flask import flash, abort
from app.but import jury_but
from app.but.cursus_but import EtudCursusBUT from app.but.cursus_but import EtudCursusBUT
from app.but.prepajury_desc import ParcoursDesc from app.but.jury_but import DecisionsProposeesAnnee
from app.but.prepajury_desc import ParcoursDesc, liste_annees, FormSemestreDesc
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
from app.models import ( from app.models import (
@ -48,101 +50,198 @@ import app.scodoc.sco_utils as scu
from app.but.prepajury_xl import ScoExcelBook from app.but.prepajury_xl import ScoExcelBook
class _Bilan: class Element:
def __init__(self): def __init__(self):
self.note = 0 self.note = None
self.resultat = 0 self.resultat = None
self.format = 0 self.format = 0
def set_note(self, note):
self.note = note
class _UE: def set_res(self, res):
self.res = res
def get_res(self):
return self.res
def get_note(self):
return self.note
class ElementUE(Element):
def __init__(self): def __init__(self):
self.bilan = None super().__init__()
class _Niveau: class ElementNiveau(Element):
def __init__(self, etudiant, niveauDesc, semestres): def __init__(self, etudiant, niveauDesc, semestres):
self.bilan = None super().__init__()
self.etudiant = etudiant self.etudiant = etudiant
self.candidates = niveauDesc.get_ues(etudiant) self.candidates = niveauDesc.get_ues(etudiant)
self.ues = collections.defaultdict(list) self.ues = collections.defaultdict(list)
def add_ue_status(self, semestre_idx, status): def add_ue_status(self, semestre_idx, status):
ue_id = status["ue"]["id"]
self.ues[semestre_idx].append(status) self.ues[semestre_idx].append(status)
self.etudiant.ues[ue_id] = status
class _Annee: class ElementAnnee(Element):
def __init__(self, etudiant, annee_desc): def __init__(self, etudiant, annee_desc):
super().__init__()
self.etudiant = etudiant self.etudiant = etudiant
self.anneeDesc = annee_desc self.anneeDesc = annee_desc
self.bilan: _Bilan = None
self.niveaux = {} self.niveaux = {}
class _Competence: class CompetenceEtudiantJury:
def __init__(self, etudiant, competenceDesc, semestres): def __init__(self, etudiant, competenceDesc, semestres):
self.descr = competenceDesc self.descr = competenceDesc
self.etudiant = etudiant self.etudiant = etudiant
self.niveaux = {} self.niveaux = {}
for niveau_id, niveauDesc in competenceDesc.niveaux.items(): for niveau_id, niveauDesc in competenceDesc.niveaux.items():
self.niveaux[niveau_id] = _Niveau(etudiant, niveauDesc, semestres) self.niveaux[niveau_id] = ElementNiveau(etudiant, niveauDesc, semestres)
etudiant.niveaux[niveau_id] = self.niveaux[niveau_id]
def getNiveau(self, niveau_id): def getNiveau(self, niveau_id):
return self.niveaux[niveau_id] return self.niveaux[niveau_id]
class _Semestre: class ElementFormsemestre(Element):
def __init__(self, formsemestre_id, formsemestre=None): def __init__(self, formsemestre_id=None, formsemestre=None):
super().__init__()
if formsemestre is None: if formsemestre is None:
formsemestre = FormSemestre.get_formsemestre(formsemestre_id) formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
self.formsemestre = formsemestre self.formsemestre = formsemestre
self.resultatsSemestreBUT: ResultatsSemestreBUT = ( self.deca = None
res_sem.load_formsemestre_results(formsemestre)
) def get_deca(self):
# self.etuds_ues = ( if self.deca is None:
# self.resultatsSemestreBUT.load_ues_inscr_parcours() self.deca = 0
# ) return self.deca
class _Etudiant: class ListeElements:
def __init__(self, ident, formation): def __init__(self):
self.elements = []
def add(self, element):
self.elements.append(element)
def last(self):
return self.elements[-1]
class EtudiantJury:
def __init__(self, ident, formation, current_formsemestre, contexte):
self.contexte = contexte
self.ident = ident self.ident = ident
self.cursus: EtudCursusBUT = EtudCursusBUT(ident, formation) self.formsemestre = current_formsemestre
self.formsemestres = [] self.formsemestres = []
self.formation = formation
self.cursus: EtudCursusBUT = EtudCursusBUT(ident, formation)
self.parcour = self.cursus.inscriptions[-1].parcour self.parcour = self.cursus.inscriptions[-1].parcour
# Variables calculées
self.history = [] self.history = []
self.competences = {} #
self.annees = [] self.formsemestre_par_semestre_idx = collections.defaultdict(lambda: ListeElements())
for inscription in self.cursus.inscriptions: # self.niveau_par_annee_et_competence : list(ListeElements) = {}
self.ues_par_annee_et_competence : list(ListeElements) = {}
#
for inscription in sorted(
self.cursus.inscriptions, key=lambda x: x.formsemestre.date_debut
):
formsemestre = inscription.formsemestre formsemestre = inscription.formsemestre
self.formsemestres.append(inscription.formsemestre.id) element_formsemestre = contexte.get_element_formsemestre(formsemestre.formsemestre_id)
Sx = f"S{formsemestre.semestre_id}" Sx = f"S{formsemestre.semestre_id}"
self.formsemestre_par_semestre_idx[formsemestre.semestre_id].add(formsemestre)
etat = inscription.etat etat = inscription.etat
if etat != "I": if etat != "I":
Sx += "(Dem)" if etat == "D" else f"({etat})" Sx += " (Dem)" if etat == "D" else f" ({etat})"
self.history.append(Sx) self.history.append(Sx)
def select(self, annee_idx=None, periode_idx=None, competence_id=None):
pass
def fill_in(self, parcourDescr, semestres): def fill_in(self, parcourDescr, semestres):
self.annees = { # Remplissage des competences
codeAnnee: _Annee(self, anneeDesc) # Remplissage des formsemestres
for codeAnnee, anneeDesc in parcourDescr.annees.items()
}
for (competence_id, competenceDesc) in parcourDescr.competences.items():
self.competences[competence_id] = _Competence(
self, competenceDesc, semestres
)
for formsemestre_id in self.formsemestres: for formsemestre_id in self.formsemestres:
semestre: _Semestre = semestres[formsemestre_id] formsemestre_desc = self.contexte.get_element_formsemestre(formsemestre_id)
ues = semestre.resultatsSemestreBUT.etud_ues(self.ident.etudid) semestre_idx = formsemestre_desc.formsemestre.semestre_id
for ue in ues: self.formsemestre_par_semestre_idx[semestre_idx] = formsemestre_desc
niveau_id = ue.niveau_competence_id for semestre_idx in range(1, 6):
competence_id = ue.niveau_competence.competence_id if semestre_idx in self.formsemestre_par_semestre_idx:
semestre_idx = ue.semestre_idx formsemestre_desc = self.formsemestre_par_semestre_idx[semestre_idx]
niveau = self.competences[competence_id].getNiveau(niveau_id) resultats = formsemestre_desc.get_resultats()
status = semestre.resultatsSemestreBUT.get_etud_ue_status( ues = resultats.etud_ues(self.ident.etudid)
self.ident.etudid, ue.id for ue in ues:
) competence_id = ue.niveau_competence.competence_id
niveau.add_ue_status(semestre_idx, status) status = resultats.get_etud_ue_status(
self.ident.etudid, ue.id
)
self.ues_par_competence_et_annee[(semestre_idx, competence_id)] = status
pass
# deca = DecisionsProposeesAnnee(self.ident, formsemestre)
# Remplissage des niveaux de compétence
# for (competence_id, item) in self.cursus.validation_par_competence_et_annee.items():
# for (annee, validation) in item.items():
# self.niveau_par_annee_and_competence[(annee, competence_id)].res = validation.code
# for annee, idx in [("BUT1", 1), ("BUT2", 2), ("BUT3", 3)]:
# formsemestre = self.formsemestre_par_semestre_idx.get(idx + 1, self.formsemestre_par_semestre_idx.get(idx, None))
# if formsemestre is not None:
# deca = DecisionsProposeesAnnee(self.ident, formsemestre)
# for (competence_id, competenceDesc) in parcourDescr.competences.items():
# self.competences[competence_id] = CompetenceEtudiantJury(
# self, competenceDesc, semestres
# )
# self.annees = {
# codeAnnee: _Annee(self, anneeDesc)
# for codeAnnee, anneeDesc in parcourDescr.annees.items()
# }
# for semestre, annee in [(2, "BUT1"), (4, "BUT2"), (6, "BUT3")]:
# if semestre in self.formsemestre_par_semestre_idx:
# self.deca[annee] = jury_but.DecisionsProposeesAnnee(
# self.ident, self.formsemestre_par_semestre_idx[semestre]
# )
# elif semestre - 1 in self.formsemestre_par_semestre_idx:
# self.deca[annee] = jury_but.DecisionsProposeesAnnee(
# self.ident, self.formsemestre_par_semestre_idx[semestre - 1]
# )
# if annee in self.deca:
# for rcue in self.deca[annee].rcues_annee:
# ue_id1 = rcue.ue_1.id
# self.notes_ues[ue_id1] = rcue.moy_ue_1
# ue_id2 = rcue.ue_2.id
# self.notes_ues[ue_id2] = rcue.moy_ue_2
# rcue_id = rcue.ue_1.niveau_competence_id
# self.notes_rcues[rcue_id] = rcue.moy_rcue
def add_formsemestre(self, formsemestre_id):
self.formsemestres.append(formsemestre_id)
def getDipl(self, codeAnnée):
return ""
def getNote(self, codeAnnée, niveau_id=None, ue_id=None):
annee = self.annees.get(codeAnnée, None)
if annee is None:
return "-"
if niveau_id is None:
return ""
elif ue_id is None:
return self.notes_rcues.get(niveau_id, "")
return self.notes_ues.get(ue_id, "")
def getRes(self, codeAnnée, niveau_id=None, ue_id=None):
if niveau_id is None:
return ""
elif ue_id is None:
return ""
return ""
def getData(self): def getData(self):
result = [ result = [
@ -160,53 +259,63 @@ class _Etudiant:
class _Compilation: class _Compilation:
def __init__(self, formsemestre: FormSemestre): def __init__(self, formsemestre: FormSemestre):
self.semestres = {} # Dictionnaire des éléments
self.parcours = {} self.inv_formsemestres = {}
# self.inv_niveaux = {}
# self.inv_ues = {}
# self.inv_annees = {}
self.inv_parcours = {}
#
formsemestre_id = formsemestre.formsemestre_id formsemestre_id = formsemestre.formsemestre_id
self.semestre: _Semestre = _Semestre(formsemestre_id, formsemestre)
self.formation: Formation = formsemestre.formation self.formation: Formation = formsemestre.formation
self.add_semestre(formsemestre_id, self.semestre) self.consider_formsemestre(formsemestre=formsemestre)
for ident in self.semestre.resultatsSemestreBUT.get_inscrits(order_by="moy"): formsemestre_desc = self.get_element_formsemestre(formsemestre_id)
etudiant: _Etudiant = _Etudiant(ident, self.formation) for ident in formsemestre_desc.get_resultats().get_inscrits(order_by="moy"):
for inscription in etudiant.cursus.inscriptions: etudiant: EtudiantJury = EtudiantJury(ident, self.formation, formsemestre, self)
# Ajout de tous les semestres de l'étudiant
for inscription in sorted(etudiant.cursus.inscriptions, key=lambda x: x.formsemestre.date_debut):
formsemestre = inscription.formsemestre formsemestre = inscription.formsemestre
if ( if (
formsemestre.formation.referentiel_competence formsemestre.formation.referentiel_competence
== self.formation.referentiel_competence == self.formation.referentiel_competence
): ):
self.add_semestre(formsemestre.id) self.consider_formsemestre(formsemestre=formsemestre)
etudiant.add_formsemestre(formsemestre.formsemestre_id)
# Prise en compte du parcours
scodocParcour = etudiant.parcour scodocParcour = etudiant.parcour
if scodocParcour is None: if scodocParcour is None:
parcourCode = "TC" parcourCode = "TC"
else: else:
parcourCode = scodocParcour.code parcourCode = scodocParcour.code
if parcourCode in self.parcours: if parcourCode in self.inv_parcours:
parcoursDesc = self.parcours[parcourCode] parcoursDesc = self.inv_parcours[parcourCode]
else: else:
parcoursDesc = ParcoursDesc(self.formation, scodocParcour) parcoursDesc = ParcoursDesc(self.formation, scodocParcour)
self.parcours[parcourCode] = parcoursDesc self.inv_parcours[parcourCode] = parcoursDesc
parcoursDesc.add_etudiant(etudiant) parcoursDesc.add_etudiant(etudiant)
# etudiant.fill_in(parcoursDesc, self.semestres) etudiant.fill_in(parcoursDesc, self)
pass
def add_semestre(self, formsemestre_id, semestre: _Semestre = None): def get_element_formsemestre(self, formsemestre_id):
if not formsemestre_id in self.semestres: return self.inv_formsemestres.get(formsemestre_id, None)
def consider_formsemestre(self, formsemestre: FormSemestre):
formsemestre_id = formsemestre.formsemestre_id
if formsemestre_id not in self.inv_formsemestres:
formsemestre_desc = FormSemestreDesc(formsemestre)
self.inv_formsemestres[formsemestre_id] = formsemestre_desc
def add_semestre(self, formsemestre_id, semestre: ElementFormsemestre = None):
if not formsemestre_id in self.ElemFormSemestres:
if semestre is None: if semestre is None:
semestre = _Semestre(formsemestre_id) semestre = ElementFormsemestre(formsemestre_id)
self.semestres[formsemestre_id] = _Semestre(formsemestre_id) self.ElemFormSemestres[formsemestre_id] = ElementFormsemestre(formsemestre_id)
def add_parcours(self, scodocParcour: ApcParcours, etudiant: _Etudiant):
parcour_code = scodocParcour.get("code", "TC")
if not parcour_code in self.parcours:
self.parcours[parcour_code] = ParcoursDesc(self.formation, scodocParcour)
self.parcours[parcour_code].add(etudiant)
def computes_decision(self): def computes_decision(self):
pass pass
def make_excel(self, filename: str): def make_excel(self, filename: str):
workbook = ScoExcelBook() workbook = ScoExcelBook()
for parcoursCode, parcours in self.parcours.items(): for parcoursCode, parcours in self.inv_parcours.items():
parcours.generate(workbook) parcours.generate(workbook)
mime, suffix = scu.get_mime_suffix("xlsx") mime, suffix = scu.get_mime_suffix("xlsx")

View File

@ -1,5 +1,6 @@
import openpyxl import openpyxl
from openpyxl.worksheet.worksheet import Worksheet from openpyxl.worksheet.worksheet import Worksheet
from app.but.prepajury_xl_format import ( from app.but.prepajury_xl_format import (
SCO_COLORS, SCO_COLORS,
FMT, FMT,
@ -11,6 +12,8 @@ from app.but.prepajury_xl_format import (
HAIR_BLACK, HAIR_BLACK,
SCO_NUMBER_FORMAT, SCO_NUMBER_FORMAT,
) )
from app.comp import res_sem
from app.comp.res_but import ResultatsSemestreBUT
from app.models import ApcCompetence, ApcParcours from app.models import ApcCompetence, ApcParcours
from app.but.prepajury_xl import ( from app.but.prepajury_xl import (
ScoExcelBook, ScoExcelBook,
@ -21,11 +24,8 @@ from app.but.prepajury_xl import (
) )
def parite(semestre_idx): UNUSED = "XXX"
return (semestre_idx + 1) % 2 liste_annees = ["BUT1", "BUT2", "BUT3"]
listeAnnees = ["BUT1", "BUT2", "BUT3"]
header_colors = { header_colors = {
"BUT1": { "BUT1": {
"BUT": SCO_COLORS.BUT1, "BUT": SCO_COLORS.BUT1,
@ -45,6 +45,25 @@ header_colors = {
} }
def parite(semestre_idx):
return (semestre_idx + 1) % 2
class FormSemestreDesc:
def __init__(self, formsemestre):
self.formsemestre = formsemestre
self.deca = None
self.resultats = None
def get_resultats(self):
if self.resultats is None:
self.resultats: ResultatsSemestreBUT = (
res_sem.load_formsemestre_results(self.formsemestre)
)
return self.resultats
class NiveauDesc: class NiveauDesc:
def __init__(self, scodocNiveau): def __init__(self, scodocNiveau):
self.fromScodoc = scodocNiveau self.fromScodoc = scodocNiveau
@ -55,6 +74,93 @@ class NiveauDesc:
if not scodocUe.is_external: if not scodocUe.is_external:
self.ue[parite(scodocUe.semestre_idx)] = scodocUe self.ue[parite(scodocUe.semestre_idx)] = scodocUe
def generate_data(
self, ws: ScoExcelSheet, row: int, etudiant: "EtudiantJury", column: int
) -> int:
for ue in self.ue:
if ue is None:
ws.set_cell(row, column, UNUSED)
ws.set_cell(row, column + 1, UNUSED)
else:
ws.set_cell(
row,
column,
etudiant.getNote(self.fromScodoc.annee, self.fromScodoc.id, ue.id),
base_signature,
)
ws.set_cell(
row,
column + 1,
etudiant.getRes(self.fromScodoc.annee, self.fromScodoc.id, ue.id),
)
column += 2
ws.set_cell(
row,
column,
etudiant.getNote(self.fromScodoc.annee, self.fromScodoc.id),
base_signature,
)
ws.set_cell(
row, column + 1, etudiant.getRes(self.fromScodoc.annee, self.fromScodoc.id)
)
return column + 2
@staticmethod
def generate_blank_data(ws: ScoExcelSheet, row: int, column: int) -> int:
ws.set_cell(row, column + 0, "UN1")
ws.set_cell(row, column + 1, "UR1")
ws.set_cell(row, column + 2, "UN2")
ws.set_cell(row, column + 3, "UR2")
ws.set_cell(row, column + 4, "R1")
ws.set_cell(row, column + 5, "R2")
column += 6
return column
@staticmethod
def generate_blank_header(ws: ScoExcelSheet, column: int, annee: str):
rcue_signature = FMT.FILL_BGCOLOR.write(
value=header_colors[annee]["RCUE"].value,
signature=base_signature,
)
ue_signature = FMT.FILL_BGCOLOR.write(
value=header_colors[annee]["UE"].value,
signature=base_signature,
)
merge = ws.get_merge_engine(start_row=2, start_column=column)
frame = ws.get_frame_engine(
start_row=2, start_column=column, thickness=SCO_BORDERTHICKNESS.BORDER_THIN
)
ws.set_cell(2, column, UNUSED, from_signature=rcue_signature)
for ue in ["UE1", "UE2"]:
frame_ue = ws.get_frame_engine(
start_row=3,
start_column=column,
thickness=SCO_BORDERTHICKNESS.BORDER_THIN,
color=SCO_COLORS.GREY,
)
merge_ue = ws.get_merge_engine(start_row=3, start_column=column)
ws.set_cell(3, column, UNUSED, ue_signature)
ws.set_cell(4, column, "Note", ue_signature)
ws.set_column_dimension_hidden(ScoExcelSheet.i2col(column - 1), True)
column += 1
ws.set_cell(4, column, "Rés.", ue_signature)
ws.set_column_dimension_hidden(ScoExcelSheet.i2col(column - 1), True)
column += 1
merge_ue.close(end_row=3, end_column=column - 1)
frame_ue.close(end_row=4, end_column=column - 1)
merge_rcue = ws.get_merge_engine(start_row=3, start_column=column)
ws.set_cell(3, column, UNUSED, rcue_signature)
ws.set_cell(4, column, UNUSED, rcue_signature)
ws.set_column_dimension_hidden(ScoExcelSheet.i2col(column - 1), True)
column += 1
ws.set_cell(4, column, UNUSED, rcue_signature)
ws.set_column_dimension_hidden(ScoExcelSheet.i2col(column - 1), True)
column += 1
merge_rcue.close(end_row=3, end_column=column - 1)
frame.close(end_row=4, end_column=column - 1)
merge.close(end_row=2, end_column=column - 1)
return column
def generate_header(self, ws: ScoExcelSheet, column: int): def generate_header(self, ws: ScoExcelSheet, column: int):
rcue_signature = FMT.FILL_BGCOLOR.write( rcue_signature = FMT.FILL_BGCOLOR.write(
value=header_colors[self.fromScodoc.annee]["RCUE"].value, value=header_colors[self.fromScodoc.annee]["RCUE"].value,
@ -68,7 +174,9 @@ class NiveauDesc:
frame = ws.get_frame_engine( frame = ws.get_frame_engine(
start_row=2, start_column=column, thickness=SCO_BORDERTHICKNESS.BORDER_THIN start_row=2, start_column=column, thickness=SCO_BORDERTHICKNESS.BORDER_THIN
) )
ws.set_cell(2, column, self.fromScodoc.libelle, from_signature=rcue_signature) ws.set_cell(
2, column, self.fromScodoc.competence.titre, from_signature=rcue_signature
)
for ue in self.ue: for ue in self.ue:
frame_ue = ws.get_frame_engine( frame_ue = ws.get_frame_engine(
start_row=3, start_row=3,
@ -140,6 +248,25 @@ class AnneeDesc:
def generate_blank_niveau(self, ws: ScoExcelSheet, column: int): def generate_blank_niveau(self, ws: ScoExcelSheet, column: int):
return column return column
def generate_data(
self, ws: ScoExcelSheet, row: int, etudiant: "EtudiantJury", column: int
) -> int:
for niveau in self.niveaux.values():
column = niveau.generate_data(ws, row, etudiant, column)
for i in range(len(self.niveaux), 6):
column = NiveauDesc.generate_blank_data(ws, row, column)
ws.set_cell(row, column + 0, "A1")
ws.set_cell(row, column + 1, etudiant.getNote(self.codeAnnee), base_signature)
ws.set_cell(row, column + 2, etudiant.getRes(self.codeAnnee))
column += 3
if self.codeAnnee == "BUT2":
ws.set_cell(row, column, etudiant.getDipl("BUT2"))
column += 1
if self.codeAnnee == "BUT3":
ws.set_cell(row, column, etudiant.getDipl("BUT3"))
column += 1
return column
def generate_header(self, ws: ScoExcelSheet, column: int): def generate_header(self, ws: ScoExcelSheet, column: int):
start = column start = column
but_signature = FMT.FILL_BGCOLOR.write( but_signature = FMT.FILL_BGCOLOR.write(
@ -162,7 +289,7 @@ class AnneeDesc:
for niveau in self.niveaux.values(): for niveau in self.niveaux.values():
column = niveau.generate_header(ws, column) column = niveau.generate_header(ws, column)
for i in range(len(self.niveaux), 6): for i in range(len(self.niveaux), 6):
column = self.generate_blank_niveau(ws, column) column = NiveauDesc.generate_blank_header(ws, column, self.codeAnnee)
merge_annee = ws.get_merge_engine(start_row=2, start_column=column) merge_annee = ws.get_merge_engine(start_row=2, start_column=column)
ws.set_cell(2, column, "Année", from_signature=but_signature) ws.set_cell(2, column, "Année", from_signature=but_signature)
# cell_format(ws.cell(2, column), but_signature, [(FMT.FONT_BOLD, True)]) # cell_format(ws.cell(2, column), but_signature, [(FMT.FONT_BOLD, True)])
@ -227,7 +354,7 @@ class ParcoursDesc:
self.competences[scodocCompetence.id] = CompetenceDesc( self.competences[scodocCompetence.id] = CompetenceDesc(
scodocCompetence scodocCompetence
) )
for codeAnnee in listeAnnees: for codeAnnee in liste_annees:
anneeDesc = AnneeDesc(codeAnnee) anneeDesc = AnneeDesc(codeAnnee)
for competence_id, competence in self.competences.items(): for competence_id, competence in self.competences.items():
anneeDesc.addNiveau(competence.getNiveaux(codeAnnee)) anneeDesc.addNiveau(competence.getNiveaux(codeAnnee))
@ -312,7 +439,7 @@ class ParcoursDesc:
def generate_header(self, ws: ScoExcelSheet): def generate_header(self, ws: ScoExcelSheet):
column: int = self.generate_etudiant_header(ws) column: int = self.generate_etudiant_header(ws)
for codeAnnee in listeAnnees: for codeAnnee in liste_annees:
column = self.annees[codeAnnee].generate_header(ws, column) column = self.annees[codeAnnee].generate_header(ws, column)
def generate(self, workbook: ScoExcelBook): def generate(self, workbook: ScoExcelBook):
@ -322,3 +449,28 @@ class ParcoursDesc:
sheet_name = "TC" sheet_name = "TC"
worksheet: ScoExcelSheet = workbook.create_sheet(sheet_name) worksheet: ScoExcelSheet = workbook.create_sheet(sheet_name)
self.generate_header(worksheet) self.generate_header(worksheet)
self.generate_etudiants(worksheet)
def generate_data(
self, ws: ScoExcelSheet, row: int, column: int, etudiant: "EtudiantJury"
):
for codeAnnee in liste_annees:
column = self.annees[codeAnnee].generate_data(ws, row, etudiant, column)
ws.set_cell(row, column, "FIN")
def generate_etudiants(self, ws: ScoExcelSheet):
ligne = 5
for etudiant in self.etudiants:
ws.set_cell(ligne, 1, etudiant.ident.id)
ws.set_cell(ligne, 2, etudiant.ident.code_nip)
ws.set_cell(ligne, 3, etudiant.ident.civilite)
ws.set_cell(ligne, 4, etudiant.ident.nom)
ws.set_cell(ligne, 5, etudiant.ident.prenom)
if etudiant.parcour:
ws.set_cell(ligne, 6, etudiant.parcour.code)
else:
ws.set_cell(ligne, 6, "-")
cursus = ", ".join(etudiant.history)
ws.set_cell(ligne, 7, cursus)
self.generate_data(ws, ligne, 10, etudiant)
ligne = ligne + 1

View File

@ -284,9 +284,9 @@ class ScoExcelSheet:
if idx < 26: # one letter key if idx < 26: # one letter key
return chr(idx + 65) return chr(idx + 65)
else: # two letters AA..ZZ else: # two letters AA..ZZ
first = (idx // 26) + 66 first = idx // 26
second = (idx % 26) + 65 second = idx % 26
return "" + chr(first) + chr(second) return "" + chr(first + 64) + chr(second + 65)
def set_cell( def set_cell(
self, self,
@ -332,6 +332,13 @@ class ScoExcelSheet:
""" """
self.ws.row_dimensions[cle].hidden = value self.ws.row_dimensions[cle].hidden = value
def set_column_dimension_hidden(self, cle, value):
"""Masque ou affiche une ligne.
cle -- identifie la colonne (1...)
value -- boolean (vrai = colonne cachée)
"""
self.ws.column_dimensions[cle].hidden = value
# def make_cell(self, value: any = None, style: Sco_Style = None, comment=None): # def make_cell(self, value: any = None, style: Sco_Style = None, comment=None):
# """Construit une cellule. # """Construit une cellule.
# value -- contenu de la cellule (texte, numérique, booléen ou date) # value -- contenu de la cellule (texte, numérique, booléen ou date)

View File

@ -90,6 +90,7 @@ class SCO_NUMBER_FORMAT(Enum):
NONE = (0, None) NONE = (0, None)
NUMBER_GENERAL = (0, FORMAT_GENERAL) NUMBER_GENERAL = (0, FORMAT_GENERAL)
NUMBER_00 = (1, FORMAT_NUMBER_00) NUMBER_00 = (1, FORMAT_NUMBER_00)
NUMBER_0 = (2, "0.0")
class SCO_HALIGN(Enum): class SCO_HALIGN(Enum):

View File

@ -47,11 +47,12 @@ 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_pv
from app.but import jury_but_view from app.but import jury_but_view
from app.but import jury_edit_manual
from app.comp import res_sem from app.comp import jury, res_sem
from app.comp.res_compat import NotesTableCompat from app.comp.res_compat import NotesTableCompat
from app.models import ScolarAutorisationInscription, ScolarNews, Scolog from app.models import Formation, ScolarAutorisationInscription, ScolarNews, Scolog
from app.models.but_refcomp import ApcNiveau, ApcParcours from app.models.but_refcomp import ApcNiveau
from app.models.config import ScoDocSiteConfig from app.models.config import ScoDocSiteConfig
from app.models.etudiants import Identite from app.models.etudiants import Identite
from app.models.formsemestre import FormSemestre from app.models.formsemestre import FormSemestre
@ -2493,7 +2494,19 @@ def formsemestre_validation_but(
erase_span = f"""<a href="{ erase_span = f"""<a href="{
url_for("notes.formsemestre_jury_but_erase", url_for("notes.formsemestre_jury_but_erase",
scodoc_dept=g.scodoc_dept, formsemestre_id=deca.formsemestre_id, scodoc_dept=g.scodoc_dept, formsemestre_id=deca.formsemestre_id,
etudid=deca.etud.id)}" class="stdlink">effacer décisions</a>""" etudid=deca.etud.id)}" class="stdlink"
title="efface décisions issues des jurys de cette année"
>effacer décisions</a>
<a style="margin-left: 16px;" class="stdlink"
href="{
url_for("notes.erase_decisions_annee_formation",
scodoc_dept=g.scodoc_dept, formation_id=deca.formsemestre.formation.id,
etudid=deca.etud.id, annee=deca.annee_but)}"
title="efface toutes décisions concernant le BUT{deca.annee_but}
de cet étudiant (même extérieures ou issues d'un redoublement)"
>effacer toutes ses décisions de BUT{deca.annee_but}</a>
"""
H.append( H.append(
f"""<div class="but_settings"> f"""<div class="but_settings">
<input type="checkbox" onchange="enable_manual_codes(this)"> <input type="checkbox" onchange="enable_manual_codes(this)">
@ -2814,15 +2827,15 @@ def formsemestre_saisie_jury(formsemestre_id: int, selected_etudid: int = None):
) )
@scodoc @scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
def formsemestre_jury_but_erase( def formsemestre_jury_but_erase(formsemestre_id: int, etudid: int = None):
formsemestre_id: int, etudid: int = None, only_one_sem=False
):
"""Supprime la décision de jury BUT pour cette année. """Supprime la décision de jury BUT pour cette année.
Si only_one_sem, n'efface que pour le formsemestre indiqué, pas les deux de l'année.
Si l'étudiant n'est pas spécifié, efface les décisions de tous les inscrits. Si l'étudiant n'est pas spécifié, efface les décisions de tous les inscrits.
Si only_one_sem, n'efface que pour le formsemestre indiqué, pas les deux de l'année.
""" """
only_one_sem = int(request.args.get("only_one_sem") or False) only_one_sem = int(request.args.get("only_one_sem") or False)
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id) formsemestre: FormSemestre = FormSemestre.query.filter_by(
id=formsemestre_id, dept_id=g.scodoc_dept_id
).first_or_404()
if not formsemestre.can_edit_jury(): if not formsemestre.can_edit_jury():
raise ScoPermissionDenied( raise ScoPermissionDenied(
dest_url=url_for( dest_url=url_for(
@ -2880,14 +2893,65 @@ def formsemestre_jury_but_erase(
if only_one_sem if only_one_sem
else """Les validations de toutes les UE, RCUE (compétences) et année else """Les validations de toutes les UE, RCUE (compétences) et année
issues de cette année scolaire seront effacées. issues de cette année scolaire seront effacées.
Les décisions des années scolaires précédentes ne seront pas modifiées.
""" """
) )
+ """<div class="warning">Cette opération est irréversible !</div>""", + """
<p>Les décisions des années scolaires précédentes ne seront pas modifiées.</p>
<div class="warning">Cette opération est irréversible !</div>
""",
cancel_url=dest_url, cancel_url=dest_url,
) )
@bp.route(
"/erase_decisions_annee_formation/<int:etudid>/<int:formation_id>/<int:annee>",
methods=["GET", "POST"],
)
@scodoc
@permission_required(Permission.ScoEtudInscrit)
def erase_decisions_annee_formation(etudid: int, formation_id: int, annee: int):
"""Efface toute les décisions d'une année pour cet étudiant"""
etud: Identite = Identite.query.get_or_404(etudid)
formation: Formation = Formation.query.filter_by(
id=formation_id, dept_id=g.scodoc_dept_id
).first_or_404()
if request.method == "POST":
jury.erase_decisions_annee_formation(etud, formation, annee, delete=True)
flash("Décisions de jury effacées")
return redirect(
url_for(
"scolar.ficheEtud",
scodoc_dept=g.scodoc_dept,
etudid=etud.id,
)
)
validations = jury.erase_decisions_annee_formation(etud, formation, annee)
return render_template(
"jury/erase_decisions_annee_formation.j2",
annee=annee,
cancel_url=url_for(
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id
),
etud=etud,
formation=formation,
validations=validations,
sco=ScoData(),
title=f"Effacer décisions de jury {etud.nom} - année {annee}",
)
@bp.route(
"/jury_delete_manual/<int:etudid>",
methods=["GET", "POST"],
)
@scodoc
@permission_required(Permission.ScoEtudInscrit)
def jury_delete_manual(etudid: int):
"""Efface toute les décisions d'une année pour cet étudiant"""
etud: Identite = Identite.query.get_or_404(etudid)
return jury_edit_manual.jury_delete_manual(etud)
sco_publish( sco_publish(
"/formsemestre_lettres_individuelles", "/formsemestre_lettres_individuelles",
sco_pv_forms.formsemestre_lettres_individuelles, sco_pv_forms.formsemestre_lettres_individuelles,