Billets absences: modernisation

This commit is contained in:
Emmanuel Viennet 2022-09-11 09:35:47 +02:00
parent f31ccbee9a
commit f5ee63dd5c
3 changed files with 104 additions and 68 deletions

View File

@ -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(

View File

@ -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(

View File

@ -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(
"""<h2>Supprimer ce billet ?</h2>""" + 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 <tt>{billet_id}</tt> 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"],
),
'<h2>Traitement du billet %s : <a class="discretelink" href="%s">%s</a></h2>'
% (
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"""<h2>Traitement du billet {billet.id} : <a class="discretelink" href="{
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id)
}">{etud.nomprenom}</a></h2>
""",
]
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(
"""<p>L'étudiant pense pouvoir justifier cette absence.<br/><em>Vérifiez le justificatif avant d'enregistrer.</em></p>"""
"""<p>L'étudiant pense pouvoir justifier cette absence.<br/>
<em>Vérifiez le justificatif avant d'enregistrer.</em></p>"""
)
F = (
"""<p><a class="stdlink" href="delete_billets_absence?billet_id=%s">Supprimer ce billet</a> (utiliser en cas d'erreur, par ex. billet en double)</p>"""
% billet_id
)
F += '<p><a class="stdlink" href="list_billets">Liste de tous les billets en attente</a></p>'
F = f"""<p><a class="stdlink" href="{
url_for("absences.delete_billets_absence",
scodoc_dept=g.scodoc_dept, billet_id=billet_id)
}">Supprimer ce billet</a>
(utiliser en cas d'erreur, par ex. billet en double)
</p>
<p><a class="stdlink" href="{
url_for("absences.list_billets", scodoc_dept=g.scodoc_dept)
}">Liste de tous les billets en attente</a>
</p>
"""
return "\n".join(H) + "<br/>" + 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(
'</div><p><a class="stdlink" href="list_billets">Autre billets en attente</a></p><h4>Billets déclarés par %s</h4>'
% (etud["nomprenom"])
f"""</div><p><a class="stdlink" href="{
url_for("absences.list_billets", scodoc_dept=g.scodoc_dept)
}">Autre billets en attente</a>
</p>
<h4>Billets déclarés par {etud.nomprenom}</h4>
"""
)
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()