# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # Gestion scolarite IUT # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Emmanuel Viennet emmanuel.viennet@viennet.net # ############################################################################## """Feuille excel pour préparation des jurys classiques (non BUT) """ import collections import time from openpyxl.cell import Cell from openpyxl.styles.numbers import FORMAT_NUMBER_00 from flask import flash, abort from flask import request from flask_login import current_user from app.but.cursus_but import EtudCursusBUT from app.comp import res_sem from app.comp.res_but import ResultatsSemestreBUT from app.comp.res_common import ResultatsSemestre from app.comp.res_compat import NotesTableCompat from app.models import ( FormSemestre, Identite, ScolarAutorisationInscription, ApcParcours, Formation, ApcCompetence, ) from app.scodoc import sco_abs from app.scodoc import codes_cursus from app.scodoc import sco_groups from app.scodoc import sco_etud from app.scodoc import sco_excel from app.scodoc import sco_formsemestre from app.scodoc import sco_cursus from app.scodoc import sco_preferences import app.scodoc.sco_utils as scu import sco_version from app.scodoc.sco_excel import ScoExcelBook, ScoExcelSheet listeAnnees = ["BUT1", "BUT2", "BUT3"] class _Cell: def __init__(self, text=None, format=None, comment=None): self.text = text self.format = format self.comment = comment def make_cell(self, worksheet: ScoExcelSheet): cell = worksheet.make_cell(self.text or "") return cell class _Header: def __init__(self): self.lines = [] self.labels = [None, None, None, None] @staticmethod def _process_item(item): if item is None: return _Cell("") if isinstance(item, _Cell): return item else: return _Cell(item) def setLabel(self, rang, label): self.labels[rang] = self._process_item(label) def add_column(self, item0=None, item1=None, item2=None, item3=None): items = list(map(lambda x: self._process_item(x), [item0, item1, item2, item3])) for rang, label in enumerate(self.labels): if not label is None: items[rang] = label self.labels[rang] = None self.lines.append(items) def extend(self, header): self.lines.extend(header.lines) def write(self, worksheet: ScoExcelSheet): row1 = [] row2 = [] row3 = [] row4 = [] for items in self.lines: row1.append(items[0].make_cell(worksheet)) row2.append(items[1].make_cell(worksheet)) row3.append(items[2].make_cell(worksheet)) row4.append(items[3].make_cell(worksheet)) worksheet.append_row(row1) worksheet.append_row(row2) worksheet.append_row(row3) worksheet.append_row(row4) class _Bilan: def __init__(self): self.note = 0 self.resultat = 0 self.format = 0 class _UE: def __init__(self): self.bilan = None class _Niveau: def __init__(self, etudiant, niveauDesc, semestres): self.bilan = None self.etudiant = etudiant self.candidates = niveauDesc.get_ues(etudiant) self.ues = collections.defaultdict(list) def add_ue_status(self, semestre_idx, status): self.ues[semestre_idx].append(status) class _Annee: def __init__(self, etudiant, annee_desc): self.etudiant = etudiant self.anneeDesc = annee_desc self.bilan: _Bilan = None self.niveaux = {} class _Competence: def __init__(self, etudiant, competenceDesc, semestres): self.descr = competenceDesc self.etudiant = etudiant self.niveaux = {} for niveau_id, niveauDesc in competenceDesc.niveaux.items(): self.niveaux[niveau_id] = _Niveau(etudiant, niveauDesc, semestres) def getNiveau(self, niveau_id): return self.niveaux[niveau_id] class _Semestre: def __init__(self, formsemestre_id, formsemestre=None): if formsemestre is None: formsemestre = FormSemestre.get_formsemestre(formsemestre_id) self.formsemestre = formsemestre self.resultatsSemestreBUT: ResultatsSemestreBUT = ( res_sem.load_formsemestre_results(formsemestre) ) # self.etuds_ues = ( # self.resultatsSemestreBUT.load_ues_inscr_parcours() # ) def parite(semestre_idx): return (semestre_idx + 1) % 2 class _NiveauDesc: def __init__(self, scodocNiveau): self.fromScodoc = scodocNiveau self.ues = {} self.ue = [None, None] for scodocUe in scodocNiveau.ues: self.ues[(scodocUe.formation_id, scodocUe.semestre_idx)] = scodocUe if not scodocUe.is_external: self.ue[parite(scodocUe.semestre_idx)] = scodocUe def generate_header(self, header): header.setLabel(1, self.fromScodoc.competence.titre) for ue in self.ue: if ue is None: header.setLabel(2, "XXX") header.add_column(item3="Note") header.add_column(item3="Res.") else: header.setLabel(2, ue.acronyme) header.add_column(item3="Note") header.add_column(item3="Res.") header.add_column(item2="RCUE", item3="Note") header.add_column(item3="Res.") return header def get_ues(self, etudiant): """get list of candidates UEs for Niveau""" ues = [None, None] for inscription in etudiant.cursus.inscriptions: formation_id = inscription.formsemestre.formation_id semestre_idx = inscription.formsemestre.semestre_id if (formation_id, semestre_idx) in self.ues: # identifier les ues cocernées ues[semestre_idx % 2] = inscription.formsemestre return ues class _CompetenceDesc: def __init__(self, scodocCompetence): self.fromScodoc: ApcCompetence = scodocCompetence self.niveaux = {} for scodocNiveau in scodocCompetence.niveaux.all(): self.niveaux[scodocNiveau.id] = _NiveauDesc(scodocNiveau) def getNiveauDesc(self, niveau_id): return self.niveaux[niveau_id] def getNiveaux(self, codeAnnee): niveaux = [] for niveau_id, niveauDesc in self.niveaux.items(): if codeAnnee == niveauDesc.fromScodoc.annee: niveaux.append(niveauDesc) return niveaux class _AnneeDesc: def __init__(self, codeAnnee): self.codeAnnee = codeAnnee self.niveaux = {} def addNiveau(self, niveaux): for niveau in niveaux: self.niveaux[niveau.fromScodoc.id] = niveau def generate_blank_niveau(self, header): header.setlabel(1, "-") for _ in range(3): header.add_column() def generate_header(self, header): for niveau in self.niveaux.values(): niveau.generate_header(header) for i in range(len(self.niveaux), 6): self.generate_blank_niveau(header) header.add_column(item1="Année", item2="Nb", item3="RCUE") header.add_column(item2="Res.") if self.codeAnnee == "BUT2": header.add_column(item1="DUT", item3="Rés.") if self.codeAnnee == "BUT3": header.add_column(item1="BUT", item3="Rés.") class _ParcoursDesc: def __init__(self, formation, scodocParcour: ApcParcours = None): self.fromScodoc: ApcParcours = scodocParcour # None pour le tronc commun 'TC' self.etudiants = [] self.competences = {} self.annees = {} if scodocParcour is None: for ( scodocCompetence ) in formation.referentiel_competence.get_competences_tronc_commun(): self.competences[scodocCompetence.id] = _CompetenceDesc( scodocCompetence ) else: query = formation.query_competences_parcour(scodocParcour) if not query is None: for scodocCompetence in query.all(): self.competences[scodocCompetence.id] = _CompetenceDesc( scodocCompetence ) for codeAnnee in listeAnnees: anneeDesc = _AnneeDesc(codeAnnee) for competence_id, competence in self.competences.items(): anneeDesc.addNiveau(competence.getNiveaux(codeAnnee)) self.annees[codeAnnee] = anneeDesc def add_etudiant(self, etudiant): if not etudiant in self.etudiants: self.etudiants.append(etudiant) def getNiveauDesc(self, competence_id, niveau_id): return self.competences[competence_id].getNiveauDesc(niveau_id) def getData(self): data = [] etudiant: _Etudiant for etudiant in self.etudiants: data.append(etudiant.getData()) return data def append_title_column(self, worksheet, cells, val1, val2, val3, val4): cells1, cells2, cells3, cells4 = cells cells1.append(worksheet.make_cell(val1)) cells2.append(worksheet.make_cell(val2)) cells3.append(worksheet.make_cell(val3)) cells4.append(worksheet.make_cell(val4)) def generate_header(self, header): titles_strings = [ "etudid", "nip", "Civ", "nom", "prenom", "parcours", "cursus", "absences", "abs. non just.", ] for title in titles_strings: header.add_column(item0=title) for codeAnnee in listeAnnees: header.setLabel(0, codeAnnee) self.annees[codeAnnee].generate_header(header) return header def generate(self, workbook: ScoExcelBook): if self.fromScodoc: sheet_name = self.fromScodoc.code else: sheet_name = "TC" worksheet: ScoExcelSheet = workbook.create_sheet(sheet_name) header: _Header = _Header() self.generate_header(header).write(worksheet) class _Etudiant: def __init__(self, ident, formation): self.ident = ident self.cursus: EtudCursusBUT = EtudCursusBUT(ident, formation) self.formsemestres = [] self.parcour = self.cursus.inscriptions[-1].parcour self.history = [] self.competences = {} self.annees = [] for inscription in self.cursus.inscriptions: formsemestre = inscription.formsemestre self.formsemestres.append(inscription.formsemestre.id) Sx = f"S{formsemestre.semestre_id}" etat = inscription.etat if etat != "I": Sx += "(Dem)" if etat == "D" else f"({etat})" self.history.append(Sx) def fill_in(self, parcourDescr, semestres): self.annees = { codeAnnee: _Annee(self, anneeDesc) 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: semestre: _Semestre = semestres[formsemestre_id] ues = semestre.resultatsSemestreBUT.etud_ues(self.ident.etudid) for ue in ues: niveau_id = ue.niveau_competence_id competence_id = ue.niveau_competence.competence_id semestre_idx = ue.semestre_idx niveau = self.competences[competence_id].getNiveau(niveau_id) status = semestre.resultatsSemestreBUT.get_etud_ue_status( self.ident.etudid, ue.id ) niveau.add_ue_status(semestre_idx, status) def getData(self): result = [ self.ident.id, self.ident.code_nip, self.ident.civilite, self.ident.nom, self.ident.prenom, self.ident.etat_civil_pv(with_paragraph=False), self.parcour.code, ", ".join(self.history), ] return result class _Compilation: def __init__(self, formsemestre: FormSemestre): self.semestres = {} self.parcours = {} formsemestre_id = formsemestre.formsemestre_id self.semestre: _Semestre = _Semestre(formsemestre_id, formsemestre) self.formation: Formation = formsemestre.formation self.add_semestre(formsemestre_id, self.semestre) for ident in self.semestre.resultatsSemestreBUT.get_inscrits(order_by="moy"): etudiant: _Etudiant = _Etudiant(ident, self.formation) for inscription in etudiant.cursus.inscriptions: formsemestre = inscription.formsemestre if ( formsemestre.formation.referentiel_competence == self.formation.referentiel_competence ): self.add_semestre(formsemestre.id) scodocParcour = etudiant.parcour if scodocParcour is None: parcourCode = "TC" else: parcourCode = scodocParcour.code if parcourCode in self.parcours: parcoursDesc = self.parcours[parcourCode] else: parcoursDesc = _ParcoursDesc(self.formation, scodocParcour) self.parcours[parcourCode] = parcoursDesc parcoursDesc.add_etudiant(etudiant) etudiant.fill_in(parcoursDesc, self.semestres) pass def add_semestre(self, formsemestre_id, semestre: _Semestre = None): if not formsemestre_id in self.semestres: if semestre is None: semestre = _Semestre(formsemestre_id) self.semestres[formsemestre_id] = _Semestre(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): pass def make_excel(self, filename: str): workbook = ScoExcelBook() for parcoursCode, parcours in self.parcours.items(): parcours.generate(workbook) mime, suffix = scu.get_mime_suffix("xlsx") xls = workbook.generate() return scu.send_file(xls, filename=filename, mime=mime, suffix=suffix) def feuille_preparation_jury_but(formsemestre_id): if not isinstance(formsemestre_id, int): abort(404) formsemestre = FormSemestre.get_formsemestre(formsemestre_id) # res: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) breakpoint() """Feuille excel pour préparation des jurys adaptée pour le BUT.""" compilation = _Compilation(formsemestre) compilation.computes_decision() filename = scu.sanitize_filename( f"""{'jury'}-{formsemestre.titre_num()}-{time.strftime("%Y-%m-%d")}""" ) return compilation.make_excel(filename)