forked from ScoDoc/ScoDoc
222 lines
7.6 KiB
Python
222 lines
7.6 KiB
Python
|
# -*- mode: python -*-
|
||
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
##############################################################################
|
||
|
#
|
||
|
# Gestion scolarite IUT
|
||
|
#
|
||
|
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||
|
#
|
||
|
# This program is free software; you can redistribute it and/or modify
|
||
|
# it under the terms of the GNU General Public License as published by
|
||
|
# the Free Software Foundation; either version 2 of the License, or
|
||
|
# (at your option) any later version.
|
||
|
#
|
||
|
# This program is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
# GNU General Public License for more details.
|
||
|
#
|
||
|
# You should have received a copy of the GNU General Public License
|
||
|
# along with this program; if not, write to the Free Software
|
||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
#
|
||
|
# Emmanuel Viennet emmanuel.viennet@viennet.net
|
||
|
#
|
||
|
##############################################################################
|
||
|
|
||
|
"""Rapport sur réussite en BUT pour enquête 2022
|
||
|
- statistiques decisions
|
||
|
"""
|
||
|
from collections import defaultdict
|
||
|
|
||
|
|
||
|
from flask import request
|
||
|
|
||
|
from app.but import jury_but
|
||
|
from app.comp import res_sem
|
||
|
from app.comp.res_compat import NotesTableCompat
|
||
|
from app.models import FormSemestre
|
||
|
from app.models.etudiants import Identite
|
||
|
|
||
|
import app.scodoc.sco_utils as scu
|
||
|
from app.scodoc import html_sco_header
|
||
|
from app.scodoc import sco_codes_parcours
|
||
|
from app.scodoc.sco_exceptions import ScoValueError
|
||
|
|
||
|
from app.scodoc import sco_preferences
|
||
|
import sco_version
|
||
|
from app.scodoc.gen_tables import GenTable
|
||
|
|
||
|
|
||
|
# Titres, ordonnés
|
||
|
INDICATEUR_NAMES = {
|
||
|
"nb_inscr": "Inscrits initiaux",
|
||
|
"nb_dem": "Démissions",
|
||
|
"nb_def": "Défaillants",
|
||
|
"nb_actifs": "Inscrits finals",
|
||
|
"nb_nar": "NAR",
|
||
|
"nb_passe_manque_rcue": "Passant avec RCUE non validé",
|
||
|
"nb_red_avec_rcue": "Redoublant avec au moins un RCUE validé",
|
||
|
"nb_red_sans_rcue": "Redoublant sans avoir validé aucun RCUE",
|
||
|
"nb_valide_tt_rcue": "Validant tous les RCUE de l'année",
|
||
|
}
|
||
|
|
||
|
|
||
|
def formsemestre_but_indicateurs(formsemestre_id: int, format="html"):
|
||
|
"""Page avec tableau indicateurs enquête ADIUT BUT 2022"""
|
||
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||
|
|
||
|
indicateurs_by_bac = but_indicateurs_by_bac(formsemestre)
|
||
|
# finalement on fait une table avec en ligne
|
||
|
# les indicateurs, et en colonne les bacs
|
||
|
bacs = sorted(indicateurs_by_bac.keys())
|
||
|
|
||
|
rows = []
|
||
|
for indicateur, titre_indicateur in INDICATEUR_NAMES.items():
|
||
|
row = {bac: indicateurs_by_bac[bac][indicateur] for bac in bacs}
|
||
|
row["titre_indicateur"] = titre_indicateur
|
||
|
rows.append(row)
|
||
|
|
||
|
tab = GenTable(
|
||
|
titles={bac: bac for bac in bacs},
|
||
|
columns_ids=["titre_indicateur"] + bacs,
|
||
|
rows=rows,
|
||
|
html_sortable=False,
|
||
|
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||
|
filename=scu.make_filename(f"Indicateurs_BUT_{formsemestre.titre_annee()}"),
|
||
|
origin=f"Généré par {sco_version.SCONAME} le {scu.timedate_human_repr()}",
|
||
|
html_caption="Indicateurs BUT annuels.",
|
||
|
base_url=f"{request.base_url}?formsemestre_id={formsemestre_id}",
|
||
|
)
|
||
|
title = "Indicateurs suivi annuel BUT"
|
||
|
t = tab.make_page(
|
||
|
title=f"""<h2 class="formsemestre">{title}</h2>""",
|
||
|
format=format,
|
||
|
with_html_headers=False,
|
||
|
)
|
||
|
if format != "html":
|
||
|
return t
|
||
|
H = [
|
||
|
html_sco_header.sco_header(page_title=title),
|
||
|
t,
|
||
|
"""<p class="help">
|
||
|
</p>""",
|
||
|
html_sco_header.sco_footer(),
|
||
|
]
|
||
|
return "\n".join(H)
|
||
|
|
||
|
|
||
|
def but_indicateurs_by_bac(formsemestre: FormSemestre) -> dict[str:dict]:
|
||
|
"""
|
||
|
L'enquête ADIUT porte sur le nombre de
|
||
|
- inscrits
|
||
|
- ayant validé tous les RCUE
|
||
|
- passant en BUT2 sans avoir validé tous les RCUE
|
||
|
- redoublants avec au moins une RCUE
|
||
|
- redoublants sans aucune RCUE
|
||
|
- NAR
|
||
|
- défaillants
|
||
|
- démissionnaires,
|
||
|
le tout découpé en FI/FA et suivant le type de bac : général/techno/pro/autre.
|
||
|
|
||
|
Le semestre est FI ou FA, donc on ne traite pas ce point.
|
||
|
On suppose qu'on est sur un semestre PAIR de BUT, dont les décisions de jury
|
||
|
ont déjà été saisies.
|
||
|
"""
|
||
|
if not formsemestre.formation.is_apc():
|
||
|
raise ScoValueError(
|
||
|
"Ce rapport doit être généré à partir d'une formation par compétences (BUT)."
|
||
|
)
|
||
|
if formsemestre.semestre_id % 2:
|
||
|
raise ScoValueError("Ce rapport doit être généré à partir d'un semestre PAIR.")
|
||
|
# Le semestre suivant (pour compter les passages)
|
||
|
next_sem_idx = formsemestre.semestre_id + 1
|
||
|
|
||
|
res: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||
|
etuds = formsemestre.get_inscrits(include_demdef=True)
|
||
|
decisions_annee = {
|
||
|
etud.id: jury_but.DecisionsProposeesAnnee(etud, formsemestre)
|
||
|
for etud in etuds
|
||
|
if res.get_etud_etat(etud.id) == scu.INSCRIT
|
||
|
}
|
||
|
# Ventilation par bac
|
||
|
etuds_by_bac = defaultdict(list) # bac : etuds
|
||
|
for etud in etuds:
|
||
|
adm = etud.admission.first()
|
||
|
bac = adm.get_bac().abbrev() if adm else "?"
|
||
|
etuds_by_bac[bac].append(etud)
|
||
|
indicateurs_by_bac = {}
|
||
|
for bac in etuds_by_bac:
|
||
|
indicateurs_by_bac[bac] = _indicateurs_enquete_but(
|
||
|
res, etuds_by_bac[bac], decisions_annee, next_sem_idx
|
||
|
)
|
||
|
indicateurs_by_bac["Total"] = _indicateurs_enquete_but(
|
||
|
res, etuds, decisions_annee, next_sem_idx
|
||
|
)
|
||
|
return indicateurs_by_bac
|
||
|
|
||
|
|
||
|
def _indicateurs_enquete_but(
|
||
|
res: NotesTableCompat,
|
||
|
etuds: list[Identite],
|
||
|
decisions_annee: dict[jury_but.DecisionsProposeesAnnee],
|
||
|
next_sem_idx: int,
|
||
|
) -> dict:
|
||
|
"""Calcule les indicateurs de l'enquête ADIUT 2022"""
|
||
|
indicateurs = {
|
||
|
"nb_inscr": len(etuds),
|
||
|
"nb_actifs": len(
|
||
|
[etud for etud in etuds if res.get_etud_etat(etud.id) == scu.INSCRIT]
|
||
|
),
|
||
|
"nb_def": len(
|
||
|
[etud for etud in etuds if res.get_etud_etat(etud.id) == scu.DEF]
|
||
|
),
|
||
|
"nb_dem": len(
|
||
|
[etud for etud in etuds if res.get_etud_etat(etud.id) == scu.DEMISSION]
|
||
|
),
|
||
|
"nb_nar": len(
|
||
|
[
|
||
|
True
|
||
|
for deca in decisions_annee.values()
|
||
|
if deca.code_valide == sco_codes_parcours.NAR
|
||
|
]
|
||
|
),
|
||
|
# Redoublants sans aucune RCUE
|
||
|
"nb_red_sans_rcue": len(
|
||
|
[
|
||
|
True
|
||
|
for deca in decisions_annee.values()
|
||
|
if (deca.nb_rcue_valides == 0)
|
||
|
and (next_sem_idx not in deca.get_autorisations_passage())
|
||
|
]
|
||
|
),
|
||
|
# Redoublants avec au moins une RCUE
|
||
|
"nb_red_avec_rcue": len(
|
||
|
[
|
||
|
True
|
||
|
for deca in decisions_annee.values()
|
||
|
if (deca.nb_rcue_valides > 0)
|
||
|
and (next_sem_idx not in deca.get_autorisations_passage())
|
||
|
]
|
||
|
),
|
||
|
# Passant (en BUT2) sans avoir validé tous les RCUE
|
||
|
"nb_passe_manque_rcue": len(
|
||
|
[
|
||
|
True
|
||
|
for deca in decisions_annee.values()
|
||
|
if (deca.nb_rcue_valides < deca.nb_competences)
|
||
|
and (next_sem_idx in deca.get_autorisations_passage())
|
||
|
]
|
||
|
),
|
||
|
# Ayant validé tous les RCUE
|
||
|
"nb_valide_tt_rcue": len(
|
||
|
[
|
||
|
True
|
||
|
for deca in decisions_annee.values()
|
||
|
if (deca.nb_rcue_valides >= deca.nb_competences)
|
||
|
]
|
||
|
),
|
||
|
}
|
||
|
return indicateurs
|