forked from ScoDoc/ScoDoc
Billets absences: modernisation
This commit is contained in:
parent
f31ccbee9a
commit
f5ee63dd5c
@ -101,6 +101,7 @@ def sidebar(etudid: int = None):
|
|||||||
etudid = request.form.get("etudid", None)
|
etudid = request.form.get("etudid", None)
|
||||||
|
|
||||||
if etudid is not None:
|
if etudid is not None:
|
||||||
|
etudi = int(etudid)
|
||||||
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
||||||
params.update(etud)
|
params.update(etud)
|
||||||
params["fiche_url"] = url_for(
|
params["fiche_url"] = url_for(
|
||||||
|
@ -39,7 +39,7 @@ from app.scodoc import sco_preferences
|
|||||||
def query_billets_etud(
|
def query_billets_etud(
|
||||||
etudid: int = None, etat: bool = None
|
etudid: int = None, etat: bool = None
|
||||||
) -> flask_sqlalchemy.BaseQuery:
|
) -> 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 etat, filtre par état.
|
||||||
Si dans un département et que la gestion des billets n'a pas été activée
|
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.
|
dans ses préférences, table toujours vide.
|
||||||
@ -48,9 +48,11 @@ def query_billets_etud(
|
|||||||
"handle_billets_abs"
|
"handle_billets_abs"
|
||||||
):
|
):
|
||||||
return []
|
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:
|
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:
|
if g.scodoc_dept is not None:
|
||||||
# jointure avec departement de l'étudiant
|
# jointure avec departement de l'étudiant
|
||||||
billets = billets.join(BilletAbsence.etudiant).filter_by(
|
billets = billets.join(BilletAbsence.etudiant).filter_by(
|
||||||
|
@ -57,7 +57,7 @@ from xml.etree import ElementTree
|
|||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import g, request
|
from flask import g, request
|
||||||
from flask import url_for
|
from flask import abort, flash, url_for
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
from app import db, log
|
from app import db, log
|
||||||
@ -70,7 +70,7 @@ from app.decorators import (
|
|||||||
permission_required,
|
permission_required,
|
||||||
permission_required_compat_scodoc7,
|
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.absences import BilletAbsence
|
||||||
from app.models.etudiants import Identite
|
from app.models.etudiants import Identite
|
||||||
from app.views import absences_bp as bp
|
from app.views import absences_bp as bp
|
||||||
@ -162,7 +162,13 @@ def index_html():
|
|||||||
@scodoc7func
|
@scodoc7func
|
||||||
def choix_semaine(group_id):
|
def choix_semaine(group_id):
|
||||||
"""Page choix semaine sur calendrier pour saisie absences d'un groupe"""
|
"""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 = [
|
H = [
|
||||||
html_sco_header.sco_header(
|
html_sco_header.sco_header(
|
||||||
page_title="Saisie des absences",
|
page_title="Saisie des absences",
|
||||||
@ -357,6 +363,9 @@ def SignaleAbsenceGrHebdo(
|
|||||||
)
|
)
|
||||||
|
|
||||||
formsemestre_id = groups_infos.formsemestre_id
|
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(
|
require_module = sco_preferences.get_preference(
|
||||||
"abs_require_module", formsemestre_id
|
"abs_require_module", formsemestre_id
|
||||||
)
|
)
|
||||||
@ -381,11 +390,8 @@ def SignaleAbsenceGrHebdo(
|
|||||||
# Si aucun etudiant n'est inscrit au module choisi...
|
# Si aucun etudiant n'est inscrit au module choisi...
|
||||||
moduleimpl_id = None
|
moduleimpl_id = None
|
||||||
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
|
||||||
sem = formsemestre.to_dict()
|
sem = formsemestre.to_dict()
|
||||||
# sem = sco_formsemestre.do_formsemestre_list({"formsemestre_id": formsemestre_id})[0]
|
|
||||||
|
|
||||||
# calcule dates jours de cette semaine
|
# calcule dates jours de cette semaine
|
||||||
# liste de dates iso "yyyy-mm-dd"
|
# liste de dates iso "yyyy-mm-dd"
|
||||||
@ -506,6 +512,8 @@ def SignaleAbsenceGrSemestre(
|
|||||||
)
|
)
|
||||||
formsemestre_id = groups_infos.formsemestre_id
|
formsemestre_id = groups_infos.formsemestre_id
|
||||||
formsemestre: FormSemestre = FormSemestre.query.get_or_404(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()
|
sem = formsemestre.to_dict()
|
||||||
require_module = sco_preferences.get_preference(
|
require_module = sco_preferences.get_preference(
|
||||||
"abs_require_module", formsemestre_id
|
"abs_require_module", formsemestre_id
|
||||||
@ -1217,7 +1225,9 @@ def XMLgetBilletsEtud(etudid=False, code_nip=False):
|
|||||||
"""Liste billets pour un etudiant"""
|
"""Liste billets pour un etudiant"""
|
||||||
log("Warning: called deprecated XMLgetBilletsEtud")
|
log("Warning: called deprecated XMLgetBilletsEtud")
|
||||||
if etudid is False:
|
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
|
etudid = etud.id
|
||||||
table = sco_abs_billets.table_billets_etud(etudid)
|
table = sco_abs_billets.table_billets_etud(etudid)
|
||||||
if table:
|
if table:
|
||||||
@ -1243,7 +1253,8 @@ def list_billets():
|
|||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
request.base_url,
|
request.base_url,
|
||||||
scu.get_request_args(),
|
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,
|
submitbutton=False,
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
@ -1264,14 +1275,14 @@ def list_billets():
|
|||||||
@scodoc7func
|
@scodoc7func
|
||||||
def delete_billets_absence(billet_id, dialog_confirmed=False):
|
def delete_billets_absence(billet_id, dialog_confirmed=False):
|
||||||
"""Supprime un billet."""
|
"""Supprime un billet."""
|
||||||
cnx = ndb.GetDBConnexion()
|
billet: BilletAbsence = (
|
||||||
billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id})
|
BilletAbsence.query.filter_by(id=billet_id)
|
||||||
if not billets:
|
.join(Identite)
|
||||||
return flask.redirect(
|
.filter_by(dept_id=g.scodoc_dept_id)
|
||||||
"list_billets?head_message=Billet%%20%s%%20inexistant !" % billet_id
|
.first_or_404()
|
||||||
)
|
)
|
||||||
if not dialog_confirmed:
|
if not dialog_confirmed:
|
||||||
tab = sco_abs_billets.table_billets(billets)
|
tab = sco_abs_billets.table_billets([billet])
|
||||||
return scu.confirm_dialog(
|
return scu.confirm_dialog(
|
||||||
"""<h2>Supprimer ce billet ?</h2>""" + tab.html(),
|
"""<h2>Supprimer ce billet ?</h2>""" + tab.html(),
|
||||||
dest_url="",
|
dest_url="",
|
||||||
@ -1279,30 +1290,35 @@ def delete_billets_absence(billet_id, dialog_confirmed=False):
|
|||||||
parameters={"billet_id": billet_id},
|
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,
|
"""Traite un billet: ajoute absence(s) et éventuellement justificatifs,
|
||||||
et change l'état du billet à 1.
|
et change l'état du billet à True.
|
||||||
NB: actuellement, les heures ne sont utilisées que pour déterminer si matin et/ou après-midi.
|
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:
|
||||||
if billet["etat"] != 0:
|
log(f"billet deja traite: {billet} !")
|
||||||
log("billet=%s" % billet)
|
|
||||||
log("billet deja traité !")
|
|
||||||
return -1
|
return -1
|
||||||
n = 0 # nombre de demi-journées d'absence ajoutées
|
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")
|
# 1-- Ajout des absences (et justifs)
|
||||||
datefin = billet["abs_end"].strftime("%d/%m/%Y")
|
datedebut = billet.abs_begin.strftime("%d/%m/%Y")
|
||||||
|
datefin = billet.abs_end.strftime("%d/%m/%Y")
|
||||||
dates = sco_abs.DateRangeISO(datedebut, datefin)
|
dates = sco_abs.DateRangeISO(datedebut, datefin)
|
||||||
# commence après-midi ?
|
# commence après-midi ?
|
||||||
if dates and billet["abs_begin"].hour > 11:
|
if dates and billet.abs_begin.hour > 11:
|
||||||
sco_abs.add_absence(
|
sco_abs.add_absence(
|
||||||
billet["etudid"],
|
billet.etudid,
|
||||||
dates[0],
|
dates[0],
|
||||||
0,
|
0,
|
||||||
estjust,
|
estjust,
|
||||||
@ -1311,9 +1327,9 @@ def _ProcessBilletAbsence(billet, estjust, description):
|
|||||||
n += 1
|
n += 1
|
||||||
dates = dates[1:]
|
dates = dates[1:]
|
||||||
# termine matin ?
|
# termine matin ?
|
||||||
if dates and billet["abs_end"].hour < 12:
|
if dates and billet.abs_end.hour < 12:
|
||||||
sco_abs.add_absence(
|
sco_abs.add_absence(
|
||||||
billet["etudid"],
|
billet.etudid,
|
||||||
dates[-1],
|
dates[-1],
|
||||||
1,
|
1,
|
||||||
estjust,
|
estjust,
|
||||||
@ -1324,14 +1340,14 @@ def _ProcessBilletAbsence(billet, estjust, description):
|
|||||||
|
|
||||||
for jour in dates:
|
for jour in dates:
|
||||||
sco_abs.add_absence(
|
sco_abs.add_absence(
|
||||||
billet["etudid"],
|
billet.etudid,
|
||||||
jour,
|
jour,
|
||||||
0,
|
0,
|
||||||
estjust,
|
estjust,
|
||||||
description=description,
|
description=description,
|
||||||
)
|
)
|
||||||
sco_abs.add_absence(
|
sco_abs.add_absence(
|
||||||
billet["etudid"],
|
billet.etudid,
|
||||||
jour,
|
jour,
|
||||||
1,
|
1,
|
||||||
estjust,
|
estjust,
|
||||||
@ -1339,9 +1355,10 @@ def _ProcessBilletAbsence(billet, estjust, description):
|
|||||||
)
|
)
|
||||||
n += 2
|
n += 2
|
||||||
|
|
||||||
# 2- change etat du billet
|
# 2- Change état du billet
|
||||||
sco_abs.billet_absence_edit(cnx, {"billet_id": billet["billet_id"], "etat": 1})
|
billet.etat = True
|
||||||
|
db.session.add(billet)
|
||||||
|
db.session.commit()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
|
||||||
@ -1351,26 +1368,27 @@ def _ProcessBilletAbsence(billet, estjust, description):
|
|||||||
@scodoc7func
|
@scodoc7func
|
||||||
def process_billet_absence_form(billet_id):
|
def process_billet_absence_form(billet_id):
|
||||||
"""Formulaire traitement d'un billet"""
|
"""Formulaire traitement d'un billet"""
|
||||||
cnx = ndb.GetDBConnexion()
|
billet: BilletAbsence = (
|
||||||
billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id})
|
BilletAbsence.query.filter_by(id=billet_id)
|
||||||
if not billets:
|
.join(Identite)
|
||||||
return flask.redirect(
|
.filter_by(dept_id=g.scodoc_dept_id)
|
||||||
"list_billets?head_message=Billet%%20%s%%20inexistant !" % billet_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]
|
etud = billet.etudiant
|
||||||
etudid = billet["etudid"]
|
|
||||||
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(
|
html_sco_header.sco_header(
|
||||||
page_title="Traitement billet d'absence de %s" % etud["nomprenom"],
|
page_title=f"Traitement billet d'absence de {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"],
|
|
||||||
),
|
),
|
||||||
|
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(
|
tf = TrivialFormulator(
|
||||||
@ -1381,7 +1399,7 @@ def process_billet_absence_form(billet_id):
|
|||||||
(
|
(
|
||||||
"etudid",
|
"etudid",
|
||||||
{"input_type": "hidden"},
|
{"input_type": "hidden"},
|
||||||
), # pour centrer l'UI sur l'étudiant
|
),
|
||||||
(
|
(
|
||||||
"estjust",
|
"estjust",
|
||||||
{"input_type": "boolcheckbox", "title": "Absences justifiées"},
|
{"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"}),
|
("description", {"input_type": "text", "size": 42, "title": "Raison"}),
|
||||||
),
|
),
|
||||||
initvalues={
|
initvalues={
|
||||||
"description": billet["description"],
|
"description": billet.description or "",
|
||||||
"estjust": billet["justified"],
|
"estjust": billet.justified,
|
||||||
"etudid": etudid,
|
"etudid": etud.id,
|
||||||
},
|
},
|
||||||
submitlabel="Enregistrer ces absences",
|
submitlabel="Enregistrer ces absences",
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
tab = sco_abs_billets.table_billets([billet], etud=etud)
|
tab = sco_abs_billets.table_billets([billet], etud=etud)
|
||||||
H.append(tab.html())
|
H.append(tab.html())
|
||||||
if billet["justified"]:
|
if billet.justified:
|
||||||
H.append(
|
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 = (
|
F = f"""<p><a class="stdlink" href="{
|
||||||
"""<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>"""
|
url_for("absences.delete_billets_absence",
|
||||||
% billet_id
|
scodoc_dept=g.scodoc_dept, billet_id=billet_id)
|
||||||
)
|
}">Supprimer ce billet</a>
|
||||||
F += '<p><a class="stdlink" href="list_billets">Liste de tous les billets en attente</a></p>'
|
(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()
|
return "\n".join(H) + "<br/>" + tf[1] + F + html_sco_header.sco_footer()
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
@ -1425,10 +1450,18 @@ def process_billet_absence_form(billet_id):
|
|||||||
elif n < 0:
|
elif n < 0:
|
||||||
H.append("Ce billet avait déjà été traité !")
|
H.append("Ce billet avait déjà été traité !")
|
||||||
H.append(
|
H.append(
|
||||||
'</div><p><a class="stdlink" href="list_billets">Autre billets en attente</a></p><h4>Billets déclarés par %s</h4>'
|
f"""</div><p><a class="stdlink" href="{
|
||||||
% (etud["nomprenom"])
|
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)
|
tab = sco_abs_billets.table_billets(billets, etud=etud)
|
||||||
H.append(tab.html())
|
H.append(tab.html())
|
||||||
return "\n".join(H) + html_sco_header.sco_footer()
|
return "\n".join(H) + html_sco_header.sco_footer()
|
||||||
|
Loading…
Reference in New Issue
Block a user