From f5ee63dd5ccab68054e2bd942af3a7cf66628b92 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 11 Sep 2022 09:35:47 +0200 Subject: [PATCH] Billets absences: modernisation --- app/scodoc/html_sidebar.py | 1 + app/scodoc/sco_abs_billets.py | 8 +- app/views/absences.py | 163 ++++++++++++++++++++-------------- 3 files changed, 104 insertions(+), 68 deletions(-) diff --git a/app/scodoc/html_sidebar.py b/app/scodoc/html_sidebar.py index 8ba6eb71..5b578d68 100644 --- a/app/scodoc/html_sidebar.py +++ b/app/scodoc/html_sidebar.py @@ -101,6 +101,7 @@ def sidebar(etudid: int = None): etudid = request.form.get("etudid", None) if etudid is not None: + etudi = int(etudid) etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0] params.update(etud) params["fiche_url"] = url_for( diff --git a/app/scodoc/sco_abs_billets.py b/app/scodoc/sco_abs_billets.py index ee7e090b..564c1268 100644 --- a/app/scodoc/sco_abs_billets.py +++ b/app/scodoc/sco_abs_billets.py @@ -39,7 +39,7 @@ from app.scodoc import sco_preferences def query_billets_etud( etudid: int = None, etat: bool = None ) -> flask_sqlalchemy.BaseQuery: - """Billets d'absences pour un étudiant. + """Billets d'absences pour un étudiant, ou tous si etudid is None. Si etat, filtre par état. Si dans un département et que la gestion des billets n'a pas été activée dans ses préférences, table toujours vide. @@ -48,9 +48,11 @@ def query_billets_etud( "handle_billets_abs" ): return [] - billets = BilletAbsence.query.filter_by(etudid=etudid) + billets = BilletAbsence.query + if etudid is not None: + billets = billets.filter_by(etudid=etudid) if etat is not None: - billets = billets.query.filter_by(etat=False) + billets = billets.filter_by(etat=False) if g.scodoc_dept is not None: # jointure avec departement de l'étudiant billets = billets.join(BilletAbsence.etudiant).filter_by( diff --git a/app/views/absences.py b/app/views/absences.py index 829fb2d4..478c93de 100644 --- a/app/views/absences.py +++ b/app/views/absences.py @@ -57,7 +57,7 @@ from xml.etree import ElementTree import flask from flask import g, request -from flask import url_for +from flask import abort, flash, url_for from flask_login import current_user from app import db, log @@ -70,7 +70,7 @@ from app.decorators import ( permission_required, permission_required_compat_scodoc7, ) -from app.models import FormSemestre, GroupDescr +from app.models import FormSemestre, GroupDescr, Partition from app.models.absences import BilletAbsence from app.models.etudiants import Identite from app.views import absences_bp as bp @@ -162,7 +162,13 @@ def index_html(): @scodoc7func def choix_semaine(group_id): """Page choix semaine sur calendrier pour saisie absences d'un groupe""" - group = GroupDescr.query.get_or_404(group_id) + group = ( + GroupDescr.query.filter_by(id=group_id) + .join(Partition) + .join(FormSemestre) + .filter_by(dept_id=g.scodoc_dept_id) + .first_or_404() + ) H = [ html_sco_header.sco_header( page_title="Saisie des absences", @@ -357,6 +363,9 @@ def SignaleAbsenceGrHebdo( ) formsemestre_id = groups_infos.formsemestre_id + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + if formsemestre.dept_id != g.scodoc_dept_id: + abort(404, "groupes inexistants dans ce département") require_module = sco_preferences.get_preference( "abs_require_module", formsemestre_id ) @@ -381,11 +390,8 @@ def SignaleAbsenceGrHebdo( # Si aucun etudiant n'est inscrit au module choisi... moduleimpl_id = None - formsemestre = FormSemestre.query.get_or_404(formsemestre_id) nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) - sem = formsemestre.to_dict() - # sem = sco_formsemestre.do_formsemestre_list({"formsemestre_id": formsemestre_id})[0] # calcule dates jours de cette semaine # liste de dates iso "yyyy-mm-dd" @@ -506,6 +512,8 @@ def SignaleAbsenceGrSemestre( ) formsemestre_id = groups_infos.formsemestre_id formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id) + if formsemestre.dept_id != g.scodoc_dept_id: + return abort(404, "groupes inexistants dans ce département") sem = formsemestre.to_dict() require_module = sco_preferences.get_preference( "abs_require_module", formsemestre_id @@ -1217,7 +1225,9 @@ def XMLgetBilletsEtud(etudid=False, code_nip=False): """Liste billets pour un etudiant""" log("Warning: called deprecated XMLgetBilletsEtud") if etudid is False: - etud = Identite.query.filter_by(code_nip=str(code_nip)).first_or_404() + etud = Identite.query.filter_by( + code_nip=str(code_nip), dept_id=g.scodoc_dept_id + ).first_or_404() etudid = etud.id table = sco_abs_billets.table_billets_etud(etudid) if table: @@ -1243,7 +1253,8 @@ def list_billets(): tf = TrivialFormulator( request.base_url, scu.get_request_args(), - (("billet_id", {"input_type": "text", "title": "Numéro du billet"}),), + (("billet_id", {"input_type": "text", "title": "Numéro du billet :"}),), + method="get", submitbutton=False, ) if tf[0] == 0: @@ -1264,14 +1275,14 @@ def list_billets(): @scodoc7func def delete_billets_absence(billet_id, dialog_confirmed=False): """Supprime un billet.""" - cnx = ndb.GetDBConnexion() - billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id}) - if not billets: - return flask.redirect( - "list_billets?head_message=Billet%%20%s%%20inexistant !" % billet_id - ) + billet: BilletAbsence = ( + BilletAbsence.query.filter_by(id=billet_id) + .join(Identite) + .filter_by(dept_id=g.scodoc_dept_id) + .first_or_404() + ) if not dialog_confirmed: - tab = sco_abs_billets.table_billets(billets) + tab = sco_abs_billets.table_billets([billet]) return scu.confirm_dialog( """

Supprimer ce billet ?

""" + tab.html(), dest_url="", @@ -1279,30 +1290,35 @@ def delete_billets_absence(billet_id, dialog_confirmed=False): parameters={"billet_id": billet_id}, ) - sco_abs.billet_absence_delete(cnx, billet_id) + db.session.delete(billet) + db.session.commit() - return flask.redirect("list_billets?head_message=Billet%20supprimé") + flash("Billet supprimé") + return flask.redirect(url_for("absences.list_billets", scodoc_dept=g.scodoc_dept)) -def _ProcessBilletAbsence(billet, estjust, description): +def _ProcessBilletAbsence( + billet: BilletAbsence, estjust: bool, description: str +) -> int: """Traite un billet: ajoute absence(s) et éventuellement justificatifs, - et change l'état du billet à 1. - NB: actuellement, les heures ne sont utilisées que pour déterminer si matin et/ou après-midi. + et change l'état du billet à True. + return: nombre de demi-journées d'absence ajoutées, -1 si billet déjà traité. + NB: actuellement, les heures ne sont utilisées que pour déterminer + si matin et/ou après-midi. """ - cnx = ndb.GetDBConnexion() - if billet["etat"] != 0: - log("billet=%s" % billet) - log("billet deja traité !") + if billet.etat: + log(f"billet deja traite: {billet} !") return -1 n = 0 # nombre de demi-journées d'absence ajoutées - # 1-- ajout des absences (et justifs) - datedebut = billet["abs_begin"].strftime("%d/%m/%Y") - datefin = billet["abs_end"].strftime("%d/%m/%Y") + + # 1-- Ajout des absences (et justifs) + datedebut = billet.abs_begin.strftime("%d/%m/%Y") + datefin = billet.abs_end.strftime("%d/%m/%Y") dates = sco_abs.DateRangeISO(datedebut, datefin) # commence après-midi ? - if dates and billet["abs_begin"].hour > 11: + if dates and billet.abs_begin.hour > 11: sco_abs.add_absence( - billet["etudid"], + billet.etudid, dates[0], 0, estjust, @@ -1311,9 +1327,9 @@ def _ProcessBilletAbsence(billet, estjust, description): n += 1 dates = dates[1:] # termine matin ? - if dates and billet["abs_end"].hour < 12: + if dates and billet.abs_end.hour < 12: sco_abs.add_absence( - billet["etudid"], + billet.etudid, dates[-1], 1, estjust, @@ -1324,14 +1340,14 @@ def _ProcessBilletAbsence(billet, estjust, description): for jour in dates: sco_abs.add_absence( - billet["etudid"], + billet.etudid, jour, 0, estjust, description=description, ) sco_abs.add_absence( - billet["etudid"], + billet.etudid, jour, 1, estjust, @@ -1339,9 +1355,10 @@ def _ProcessBilletAbsence(billet, estjust, description): ) n += 2 - # 2- change etat du billet - sco_abs.billet_absence_edit(cnx, {"billet_id": billet["billet_id"], "etat": 1}) - + # 2- Change état du billet + billet.etat = True + db.session.add(billet) + db.session.commit() return n @@ -1351,26 +1368,27 @@ def _ProcessBilletAbsence(billet, estjust, description): @scodoc7func def process_billet_absence_form(billet_id): """Formulaire traitement d'un billet""" - cnx = ndb.GetDBConnexion() - billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id}) - if not billets: - return flask.redirect( - "list_billets?head_message=Billet%%20%s%%20inexistant !" % billet_id + billet: BilletAbsence = ( + BilletAbsence.query.filter_by(id=billet_id) + .join(Identite) + .filter_by(dept_id=g.scodoc_dept_id) + .first() + ) + if billet is None: + raise ScoValueError( + f"Aucun billet avec le numéro {billet_id} dans ce département.", + dest_url=url_for("absences.list_billets", scodoc_dept=g.scodoc_dept), ) - billet = billets[0] - etudid = billet["etudid"] - etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0] + etud = billet.etudiant H = [ html_sco_header.sco_header( - page_title="Traitement billet d'absence de %s" % etud["nomprenom"], - ), - '

Traitement du billet %s : %s

' - % ( - billet_id, - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid), - etud["nomprenom"], + page_title=f"Traitement billet d'absence de {etud.nomprenom}", ), + f"""

Traitement du billet {billet.id} : {etud.nomprenom}

+ """, ] tf = TrivialFormulator( @@ -1381,7 +1399,7 @@ def process_billet_absence_form(billet_id): ( "etudid", {"input_type": "hidden"}, - ), # pour centrer l'UI sur l'étudiant + ), ( "estjust", {"input_type": "boolcheckbox", "title": "Absences justifiées"}, @@ -1389,24 +1407,31 @@ def process_billet_absence_form(billet_id): ("description", {"input_type": "text", "size": 42, "title": "Raison"}), ), initvalues={ - "description": billet["description"], - "estjust": billet["justified"], - "etudid": etudid, + "description": billet.description or "", + "estjust": billet.justified, + "etudid": etud.id, }, submitlabel="Enregistrer ces absences", ) if tf[0] == 0: tab = sco_abs_billets.table_billets([billet], etud=etud) H.append(tab.html()) - if billet["justified"]: + if billet.justified: H.append( - """

L'étudiant pense pouvoir justifier cette absence.
Vérifiez le justificatif avant d'enregistrer.

""" + """

L'étudiant pense pouvoir justifier cette absence.
+ Vérifiez le justificatif avant d'enregistrer.

""" ) - F = ( - """

Supprimer ce billet (utiliser en cas d'erreur, par ex. billet en double)

""" - % billet_id - ) - F += '

Liste de tous les billets en attente

' + F = f"""

Supprimer ce billet + (utiliser en cas d'erreur, par ex. billet en double) +

+

Liste de tous les billets en attente +

+ """ return "\n".join(H) + "
" + tf[1] + F + html_sco_header.sco_footer() elif tf[0] == -1: @@ -1425,10 +1450,18 @@ def process_billet_absence_form(billet_id): elif n < 0: H.append("Ce billet avait déjà été traité !") H.append( - '

Autre billets en attente

Billets déclarés par %s

' - % (etud["nomprenom"]) + f"""

Autre billets en attente +

+

Billets déclarés par {etud.nomprenom}

+ """ + ) + billets = ( + BilletAbsence.query.filter_by(etudid=etud.id) + .join(Identite) + .filter_by(dept_id=g.scodoc_dept_id) ) - billets = sco_abs.billet_absence_list(cnx, {"etudid": etud["etudid"]}) tab = sco_abs_billets.table_billets(billets, etud=etud) H.append(tab.html()) return "\n".join(H) + html_sco_header.sco_footer()