diff --git a/app/but/forms/jury_but_forms.py b/app/but/forms/jury_but_forms.py new file mode 100644 index 00000000..0f371960 --- /dev/null +++ b/app/but/forms/jury_but_forms.py @@ -0,0 +1,18 @@ +############################################################################## +# ScoDoc +# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved. +# See LICENSE +############################################################################## + +"""ScoDoc 9.3 : Formulaires / jurys BUT +""" + + +from flask_wtf import FlaskForm +from wtforms import SubmitField + + +class FormSemestreValidationAutoBUTForm(FlaskForm): + "simple form de confirmation" + submit = SubmitField("Lancer le calcul") + cancel = SubmitField("Annuler") diff --git a/app/but/jury_but.py b/app/but/jury_but.py index 391f77ed..8ab3a213 100644 --- a/app/but/jury_but.py +++ b/app/but/jury_but.py @@ -259,7 +259,8 @@ class DecisionsProposeesAnnee(DecisionsProposees): ) "le nb de comp. sous la barre de 8/20" # année ADM si toutes RCUE validées (sinon PASD) - admis = self.nb_validables == self.nb_competences + self.admis = self.nb_validables == self.nb_competences + "vrai si l'année est réussie, tous niveaux validables" self.valide_moitie_rcue = self.nb_validables > (self.nb_competences // 2) # Peut passer si plus de la moitié validables et tous > 8 self.passage_de_droit = self.valide_moitie_rcue and (self.nb_rcues_under_8 == 0) @@ -273,7 +274,7 @@ class DecisionsProposeesAnnee(DecisionsProposees): expl_rcues = ( f"{self.nb_validables} niveau validable(s) sur {self.nb_competences}" ) - if admis: + if self.admis: self.codes = [sco_codes.ADM] + self.codes self.explanation = expl_rcues elif self.passage_de_droit: diff --git a/app/but/jury_but_recap.py b/app/but/jury_but_recap.py index b9ed57a3..38e1fd68 100644 --- a/app/but/jury_but_recap.py +++ b/app/but/jury_but_recap.py @@ -18,10 +18,8 @@ from app.but.jury_but import ( ) from app.comp.res_but import ResultatsSemestreBUT from app.comp import res_sem -from app.models.but_validations import RegroupementCoherentUE from app.models.etudiants import Identite from app.models.formsemestre import FormSemestre -from app.models.ues import UniteEns from app.scodoc.sco_codes_parcours import ( BUT_BARRE_RCUE, @@ -79,8 +77,21 @@ def formsemestre_saisie_jury_but( formsemestre_id=formsemestre2.id ), ] - H.append(table_html) - H.append(html_sco_header.sco_footer()) + H.append( + f""" + + {table_html} + + + + {html_sco_header.sco_footer()} + """ + ) return "\n".join(H) diff --git a/app/but/jury_but_validation_auto.py b/app/but/jury_but_validation_auto.py new file mode 100644 index 00000000..99512168 --- /dev/null +++ b/app/but/jury_but_validation_auto.py @@ -0,0 +1,34 @@ +############################################################################## +# ScoDoc +# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved. +# See LICENSE +############################################################################## + +"""Jury BUT: clacul des décisions de jury annuelles "automatiques" +""" + +from flask import g, url_for + +from app import db +from app.but import jury_but +from app.models.etudiants import Identite +from app.models.formsemestre import FormSemestre +from app.scodoc.sco_exceptions import ScoValueError + + +def formsemestre_validation_auto_but(formsemestre: FormSemestre) -> int: + """Calcul automatique des décisions de jury sur une année BUT. + Returns: nombre d'étudiants "admis" + """ + if not formsemestre.formation.is_apc(): + raise ScoValueError("fonction réservée aux formations BUT") + nb_admis = 0 + for etudid in formsemestre.etuds_inscriptions: + etud: Identite = Identite.query.get(etudid) + deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre) + if deca.admis: # année réussie + deca.record_all() + nb_admis += 1 + + db.session.commit() + return nb_admis diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index 6b41b761..961d789b 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -3963,6 +3963,11 @@ table.table_recap td.evaluation.non_inscrit { color: rgb(101, 101, 101); } +div.table_jury_but_links { + margin-top: 16px; + margin-bottom: 16px; +} + /* ------------- Tableau etat evals ------------ */ div.evaluations_recap table.evaluations_recap { diff --git a/app/templates/but/formsemestre_validation_auto_but.html b/app/templates/but/formsemestre_validation_auto_but.html new file mode 100644 index 00000000..c9397fc0 --- /dev/null +++ b/app/templates/but/formsemestre_validation_auto_but.html @@ -0,0 +1,30 @@ +{# -*- mode: jinja-html -*- #} +{% extends "sco_page.html" %} +{% import 'bootstrap/wtf.html' as wtf %} + +{% block styles %} +{{super()}} +{% endblock %} + +{% block app_content %} + +

Calcul automatique des décisions de jury annuelle BUT

+ +

+ Il est nécessaire de relire soigneusement les décisions à l'issue de cette procédure ! +

+ + +
+
+ {{ wtf.quick_form(form) }} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/app/views/notes.py b/app/views/notes.py index 199a323f..f00758b6 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -41,7 +41,8 @@ from flask import abort, flash, jsonify, redirect, render_template, url_for from flask import current_app, g, request from flask_login import current_user -from app.but import jury_but +from app.but import jury_but, jury_but_validation_auto +from app.but.forms import jury_but_forms from app.comp import res_sem from app.comp.res_but import ResultatsSemestreBUT from app.comp.res_compat import NotesTableCompat @@ -2224,7 +2225,7 @@ def formsemestre_validation_but(formsemestre_id: int, etudid: int): "Form. saisie décision jury semestre BUT" if not sco_permissions_check.can_validate_sem(formsemestre_id): return scu.confirm_dialog( - message="

Opération non autorisée pour %s" % current_user, + message=f"

Opération non autorisée pour {current_user}", dest_url=url_for( "notes.formsemestre_status", scodoc_dept=g.scodoc_dept, @@ -2274,7 +2275,8 @@ def formsemestre_validation_but(formsemestre_id: int, etudid: int):

Décision de jury pour l'année : { - _gen_but_select("code_annee", deca.codes, deca.code_valide, disabled=True, klass="manual") + _gen_but_select("code_annee", deca.codes, deca.code_valide, + disabled=True, klass="manual") } ({'non ' if deca.code_valide is None else ''}enregistrée)
@@ -2396,6 +2398,45 @@ def _gen_but_niveau_ue(
""" +@bp.route( + "/formsemestre_validation_auto_but/", methods=["GET", "POST"] +) +@scodoc +@permission_required(Permission.ScoView) +def formsemestre_validation_auto_but(formsemestre_id: int = None): + "Saisie automatique des décisions de jury BUT" + if not sco_permissions_check.can_validate_sem(formsemestre_id): + return scu.confirm_dialog( + message=f"

Opération non autorisée pour {current_user}", + dest_url=url_for( + "notes.formsemestre_status", + scodoc_dept=g.scodoc_dept, + formsemestre_id=formsemestre_id, + ), + ) + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + form = jury_but_forms.FormSemestreValidationAutoBUTForm() + if request.method == "POST": + if not form.cancel.data: + nb_admis = jury_but_validation_auto.formsemestre_validation_auto_but( + formsemestre + ) + flash(f"Décisions enregistrées ({nb_admis} admis)") + return redirect( + url_for( + "notes.formsemestre_saisie_jury", + scodoc_dept=g.scodoc_dept, + formsemestre_id=formsemestre_id, + ) + ) + return render_template( + "but/formsemestre_validation_auto_but.html", + form=form, + sco=ScoData(formsemestre=formsemestre), + title=f"Calcul automatique jury BUT", + ) + + @bp.route("/formsemestre_validate_previous_ue", methods=["GET", "POST"]) @scodoc @permission_required(Permission.ScoView)