Fix abs methods

This commit is contained in:
Emmanuel Viennet 2021-07-09 10:26:31 +02:00
parent 26ccb0bbb8
commit ff9ab2b751
6 changed files with 148 additions and 105 deletions

View File

@ -145,7 +145,7 @@ class ddmmyyyy:
"iso8601 representation of the date" "iso8601 representation of the date"
return "%04d-%02d-%02d" % (self.year, self.month, self.day) return "%04d-%02d-%02d" % (self.year, self.month, self.day)
def next(self, days=1): def next_day(self, days=1):
"date for the next day (nota: may be a non workable day)" "date for the next day (nota: may be a non workable day)"
day = self.day + days day = self.day + days
month = self.month month = self.month
@ -179,7 +179,7 @@ class ddmmyyyy:
def next_monday(self): def next_monday(self):
"date of next monday" "date of next monday"
return self.next((7 - self.weekday) % 7) return self.next_day((7 - self.weekday) % 7)
def prev_monday(self): def prev_monday(self):
"date of last monday, but on sunday, pick next monday" "date of last monday, but on sunday, pick next monday"
@ -213,7 +213,7 @@ def DateRangeISO(context, date_beg, date_end, workable=1):
while cur <= end: while cur <= end:
if (not workable) or cur.iswork(): if (not workable) or cur.iswork():
r.append(cur) r.append(cur)
cur = cur.next() cur = cur.next_day()
return map(lambda x: x.ISO(), r) return map(lambda x: x.ISO(), r)
@ -231,7 +231,7 @@ def day_names(context):
def next_iso_day(context, date): def next_iso_day(context, date):
"return date after date" "return date after date"
d = ddmmyyyy(date, fmt="iso", work_saturday=is_work_saturday(context)) d = ddmmyyyy(date, fmt="iso", work_saturday=is_work_saturday(context))
return d.next().ISO() return d.next_day().ISO()
def YearTable( def YearTable(
@ -860,7 +860,7 @@ def MonthTableBody(
cc.append("</td>") cc.append("</td>")
cell = string.join(cc, "") cell = string.join(cc, "")
if day == "D": if day == "D":
monday = monday.next(7) monday = monday.next_day(7)
if ( if (
weeknum == current_weeknum weeknum == current_weeknum
and current_year == year and current_year == year
@ -894,7 +894,7 @@ def MonthTableBody(
weeknum += " currentweek" weeknum += " currentweek"
if day == "D": if day == "D":
monday = monday.next(7) monday = monday.next_day(7)
T.append( T.append(
'<tr bgcolor="%s" class="wk%s" %s><td class="calday">%d%s</td>' '<tr bgcolor="%s" class="wk%s" %s><td class="calday">%d%s</td>'
% (bgcolor, weekclass, attrs, d, day) % (bgcolor, weekclass, attrs, d, day)

View File

@ -737,7 +737,9 @@ def CalAbs(context, REQUEST=None): # etud implied
datedebut = str(anneescolaire) + "-08-31" datedebut = str(anneescolaire) + "-08-31"
datefin = str(anneescolaire + 1) + "-07-31" datefin = str(anneescolaire + 1) + "-07-31"
nbabs = sco_abs.CountAbs(context, etudid=etudid, debut=datedebut, fin=datefin) nbabs = sco_abs.CountAbs(context, etudid=etudid, debut=datedebut, fin=datefin)
nbabsjust = sco_abs.CountAbsJust(context, etudid=etudid, debut=datedebut, fin=datefin) nbabsjust = sco_abs.CountAbsJust(
context, etudid=etudid, debut=datedebut, fin=datefin
)
events = [] events = []
for a in sco_abs.ListeAbsJust(context, etudid=etudid, datedebut=datedebut): for a in sco_abs.ListeAbsJust(context, etudid=etudid, datedebut=datedebut):
events.append( events.append(
@ -1042,77 +1044,3 @@ def _TablesAbsEtud(
columns_ids.append("justlink") columns_ids.append("justlink")
return titles, columns_ids, absnonjust, absjust return titles, columns_ids, absnonjust, absjust
def index_html(context, REQUEST=None):
"""Gestionnaire absences, page principale"""
# crude portage from 1999 DTML
sems = sco_formsemestre.do_formsemestre_list(context)
authuser = REQUEST.AUTHENTICATED_USER
H = [
html_sco_header.sco_header(
context,
REQUEST,
page_title="Gestion des absences",
cssstyles=["css/calabs.css"],
javascripts=["js/calabs.js"],
),
"""<h2>Gestion des Absences</h2>""",
]
if not sems:
H.append(
"""<p class="warning">Aucun semestre défini (ou aucun groupe d'étudiant)</p>"""
)
else:
H.append(
"""<ul><li><a href="EtatAbsences">Afficher l'état des absences (pour tout un groupe)</a></li>"""
)
if sco_preferences.get_preference(context, "handle_billets_abs"):
H.append(
"""<li><a href="listeBillets">Traitement des billets d'absence en attente</a></li>"""
)
H.append(
"""<p>Pour signaler, annuler ou justifier une absence, choisissez d'abord l'étudiant concerné:</p>"""
)
H.append(sco_find_etud.form_search_etud(context, REQUEST))
if authuser.has_permission(Permission.ScoAbsChange):
H.extend(
(
"""<hr/>
<form action="SignaleAbsenceGrHebdo" id="formw">
<input type="hidden" name="destination" value="%s"/>
<p>
<span style="font-weight: bold; font-size:120%%;">
Saisie par semaine </span> - Choix du groupe:
<input name="datelundi" type="hidden" value="x"/>
"""
% REQUEST.URL0,
formChoixSemestreGroupe(context),
"</p>",
cal_select_week(context, REQUEST=REQUEST),
"""<p class="help">Sélectionner le groupe d'étudiants, puis cliquez sur une semaine pour
saisir les absences de toute cette semaine.</p>
</form>""",
)
)
else:
H.append(
"""<p class="scoinfo">Vous n'avez pas l'autorisation d'ajouter, justifier ou supprimer des absences.</p>"""
)
H.append(html_sco_header.sco_footer(context, REQUEST))
return "\n".join(H)
def cal_select_week(context, year=None, REQUEST=None):
"display calendar allowing week selection"
if not year:
year = scu.AnneeScolaire(REQUEST)
sems = sco_formsemestre.do_formsemestre_list(context)
if not sems:
js = ""
else:
js = 'onmouseover="highlightweek(this);" onmouseout="deselectweeks();" onclick="wclick(this);"'
C = sco_abs.YearTable(context, int(year), dayattributes=js)
return C

View File

@ -31,8 +31,9 @@
import urllib import urllib
import cgi import cgi
# Rewritten from ancient DTML code
from flask import current_app from flask import current_app
from flask import g
from flask import url_for
from app.scodoc.notes_log import log from app.scodoc.notes_log import log
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
@ -805,7 +806,11 @@ def _make_listes_sem(context, sem, REQUEST=None, with_absences=True):
first_monday = sco_abs.ddmmyyyy(sem["date_debut"]).prev_monday() first_monday = sco_abs.ddmmyyyy(sem["date_debut"]).prev_monday()
FA = [] # formulaire avec menu saisi absences FA = [] # formulaire avec menu saisi absences
FA.append( FA.append(
'<td><form action="Absences/SignaleAbsenceGrSemestre" method="get">' '<td><form action="{}" method="get">'.format(
url_for(
"absences.SignaleAbsenceGrSemestre", scodoc_dept=g.scodoc_dept
)
)
) )
FA.append( FA.append(
'<input type="hidden" name="datefin" value="%(date_fin)s"/>' % sem '<input type="hidden" name="datefin" value="%(date_fin)s"/>' % sem
@ -820,7 +825,7 @@ def _make_listes_sem(context, sem, REQUEST=None, with_absences=True):
date = first_monday date = first_monday
for jour in sco_abs.day_names(context): for jour in sco_abs.day_names(context):
FA.append('<option value="%s">%s</option>' % (date, jour)) FA.append('<option value="%s">%s</option>' % (date, jour))
date = date.next() date = date.next_day()
FA.append("</select>") FA.append("</select>")
FA.append( FA.append(
'<a href="Absences/EtatAbsencesGr?group_ids=%%(group_id)s&debut=%(date_debut)s&fin=%(date_fin)s">état</a>' '<a href="Absences/EtatAbsencesGr?group_ids=%%(group_id)s&debut=%(date_debut)s&fin=%(date_fin)s">état</a>'

View File

@ -918,7 +918,7 @@ def form_choix_jour_saisie_hebdo(
sel = "" sel = ""
i += 1 i += 1
FA.append('<option value="%s" %s>%s</option>' % (date, sel, jour)) FA.append('<option value="%s" %s>%s</option>' % (date, sel, jour))
date = date.next() date = date.next_day()
FA.append("</select>") FA.append("</select>")
FA.append("</form>") FA.append("</form>")
return "\n".join(FA) return "\n".join(FA)

View File

@ -911,7 +911,7 @@ def query_portal(req, msg="Portail Apogee", timeout=3):
return data return data
def AnneeScolaire(REQUEST=None): def AnneeScolaire(REQUEST=None): # TODO remplacer REQUEST #sco8
"annee de debut de l'annee scolaire courante" "annee de debut de l'annee scolaire courante"
if REQUEST and REQUEST.form.has_key("sco_year"): if REQUEST and REQUEST.form.has_key("sco_year"):
year = REQUEST.form["sco_year"] year = REQUEST.form["sco_year"]

View File

@ -46,6 +46,7 @@ L'API de plus bas niveau est en gros:
""" """
from __future__ import absolute_import
import string import string
import re import re
import time import time
@ -53,7 +54,7 @@ import datetime
import dateutil import dateutil
import dateutil.parser import dateutil.parser
import calendar import calendar
import urllib import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
import cgi import cgi
import jaxml import jaxml
@ -87,6 +88,7 @@ from app.scodoc import sco_compute_moy
from app.scodoc import sco_core from app.scodoc import sco_core
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.scodoc import sco_excel from app.scodoc import sco_excel
from app.scodoc import sco_find_etud
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups from app.scodoc import sco_groups
from app.scodoc import sco_groups_view from app.scodoc import sco_groups_view
@ -100,11 +102,13 @@ CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS
context = ScoDoc7Context("absences") context = ScoDoc7Context("absences")
def sco_publish(route, function, permission): def sco_publish(route, function, permission, methods=["GET"]):
"""Declare a route for a python function, """Declare a route for a python function,
protected by permission and called following ScoDoc 7 Zope standards. protected by permission and called following ScoDoc 7 Zope standards.
""" """
bp.route(route)(permission_required(permission)(scodoc7func(context)(function))) return bp.route(route, methods=methods)(
permission_required(permission)(scodoc7func(context)(function))
)
def _toboolean(x): def _toboolean(x):
@ -118,28 +122,134 @@ def _toboolean(x):
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
sco_publish("/index_html", sco_abs_views.index_html, Permission.ScoView)
@bp.route("/")
@bp.route("/index_html")
@permission_required(Permission.ScoView)
@scodoc7func(context)
def index_html(context, REQUEST=None):
"""Gestionnaire absences, page principale"""
# crude portage from 1999 DTML
sems = sco_formsemestre.do_formsemestre_list(context)
authuser = REQUEST.AUTHENTICATED_USER
H = [
html_sco_header.sco_header(
context,
REQUEST,
page_title="Gestion des absences",
cssstyles=["css/calabs.css"],
javascripts=["js/calabs.js"],
),
"""<h2>Gestion des Absences</h2>""",
]
if not sems:
H.append(
"""<p class="warning">Aucun semestre défini (ou aucun groupe d'étudiant)</p>"""
)
else:
H.append(
"""<ul><li><a href="EtatAbsences">Afficher l'état des absences (pour tout un groupe)</a></li>"""
)
if sco_preferences.get_preference(context, "handle_billets_abs"):
H.append(
"""<li><a href="listeBillets">Traitement des billets d'absence en attente</a></li>"""
)
H.append(
"""<p>Pour signaler, annuler ou justifier une absence, choisissez d'abord l'étudiant concerné:</p>"""
)
H.append(sco_find_etud.form_search_etud(context, REQUEST))
if authuser.has_permission(Permission.ScoAbsChange):
H.extend(
(
"""<hr/>
<form action="SignaleAbsenceGrHebdo" id="formw">
<input type="hidden" name="destination" value="%s"/>
<p>
<span style="font-weight: bold; font-size:120%%;">
Saisie par semaine </span> - Choix du groupe:
<input name="datelundi" type="hidden" value="x"/>
"""
% REQUEST.URL0,
sco_abs_views.formChoixSemestreGroupe(context),
"</p>",
cal_select_week(context, REQUEST=REQUEST),
"""<p class="help">Sélectionner le groupe d'étudiants, puis cliquez sur une semaine pour
saisir les absences de toute cette semaine.</p>
</form>""",
)
)
else:
H.append(
"""<p class="scoinfo">Vous n'avez pas l'autorisation d'ajouter, justifier ou supprimer des absences.</p>"""
)
H.append(html_sco_header.sco_footer(context, REQUEST))
return "\n".join(H)
def cal_select_week(context, year=None, REQUEST=None):
"display calendar allowing week selection"
if not year:
year = scu.AnneeScolaire(REQUEST)
sems = sco_formsemestre.do_formsemestre_list(context)
if not sems:
js = ""
else:
js = 'onmouseover="highlightweek(this);" onmouseout="deselectweeks();" onclick="wclick(this);"'
C = sco_abs.YearTable(context, int(year), dayattributes=js)
return C
sco_publish("/EtatAbsences", sco_abs_views.EtatAbsences, Permission.ScoView) sco_publish("/EtatAbsences", sco_abs_views.EtatAbsences, Permission.ScoView)
sco_publish("/CalAbs", sco_abs_views.CalAbs, Permission.ScoView) sco_publish("/CalAbs", sco_abs_views.CalAbs, Permission.ScoView)
sco_publish( sco_publish(
"/SignaleAbsenceEtud", sco_abs_views.SignaleAbsenceEtud, Permission.ScoAbsChange "/SignaleAbsenceEtud",
sco_abs_views.SignaleAbsenceEtud,
Permission.ScoAbsChange,
methods=["GET", "POST"],
) )
sco_publish( sco_publish(
"/doSignaleAbsence", sco_abs_views.doSignaleAbsence, Permission.ScoAbsChange "/doSignaleAbsence",
sco_abs_views.doSignaleAbsence,
Permission.ScoAbsChange,
methods=["GET", "POST"],
) )
sco_publish( sco_publish(
"/JustifAbsenceEtud", sco_abs_views.JustifAbsenceEtud, Permission.ScoAbsChange "/JustifAbsenceEtud",
sco_abs_views.JustifAbsenceEtud,
Permission.ScoAbsChange,
methods=["GET", "POST"],
) )
sco_publish("/doJustifAbsence", sco_abs_views.doJustifAbsence, Permission.ScoAbsChange)
sco_publish( sco_publish(
"/AnnuleAbsenceEtud", sco_abs_views.AnnuleAbsenceEtud, Permission.ScoAbsChange "/doJustifAbsence",
sco_abs_views.doJustifAbsence,
Permission.ScoAbsChange,
methods=["GET", "POST"],
)
sco_publish(
"/AnnuleAbsenceEtud",
sco_abs_views.AnnuleAbsenceEtud,
Permission.ScoAbsChange,
methods=["GET", "POST"],
)
sco_publish(
"/doAnnuleAbsence",
sco_abs_views.doAnnuleAbsence,
Permission.ScoAbsChange,
methods=["GET", "POST"],
)
sco_publish(
"/doAnnuleJustif",
sco_abs_views.doAnnuleJustif,
Permission.ScoAbsChange,
methods=["GET", "POST"],
) )
sco_publish("/doAnnuleAbsence", sco_abs_views.doAnnuleAbsence, Permission.ScoAbsChange)
sco_publish("/doAnnuleJustif", sco_abs_views.doAnnuleJustif, Permission.ScoAbsChange)
sco_publish( sco_publish(
"/AnnuleAbsencesDatesNoJust", "/AnnuleAbsencesDatesNoJust",
sco_abs_views.AnnuleAbsencesDatesNoJust, sco_abs_views.AnnuleAbsencesDatesNoJust,
Permission.ScoAbsChange, Permission.ScoAbsChange,
methods=["GET", "POST"],
) )
sco_publish("/ListeAbsEtud", sco_abs_views.ListeAbsEtud, Permission.ScoView) sco_publish("/ListeAbsEtud", sco_abs_views.ListeAbsEtud, Permission.ScoView)
@ -155,7 +265,7 @@ sco_publish("/CountAbs", sco_abs.CountAbs, Permission.ScoView)
sco_publish("/CountAbsJust", sco_abs.CountAbsJust, Permission.ScoView) sco_publish("/CountAbsJust", sco_abs.CountAbsJust, Permission.ScoView)
@bp.route("/doSignaleAbsenceGrSemestre") @bp.route("/doSignaleAbsenceGrSemestre", methods=["GET", "POST"])
@permission_required(Permission.ScoAbsChange) @permission_required(Permission.ScoAbsChange)
@scodoc7func(context) @scodoc7func(context)
def doSignaleAbsenceGrSemestre( def doSignaleAbsenceGrSemestre(
@ -198,7 +308,7 @@ def doSignaleAbsenceGrSemestre(
# ------------ HTML Interfaces # ------------ HTML Interfaces
@bp.route("/SignaleAbsenceGrHebdo") @bp.route("/SignaleAbsenceGrHebdo", methods=["GET", "POST"])
@permission_required(Permission.ScoAbsChange) @permission_required(Permission.ScoAbsChange)
@scodoc7func(context) @scodoc7func(context)
def SignaleAbsenceGrHebdo( def SignaleAbsenceGrHebdo(
@ -223,7 +333,7 @@ def SignaleAbsenceGrHebdo(
base_url = "SignaleAbsenceGrHebdo?datelundi=%s&%s&destination=%s" % ( base_url = "SignaleAbsenceGrHebdo?datelundi=%s&%s&destination=%s" % (
datelundi, datelundi,
groups_infos.groups_query_args, groups_infos.groups_query_args,
urllib.quote(destination), six.moves.urllib.parse.quote(destination),
) )
formsemestre_id = groups_infos.formsemestre_id formsemestre_id = groups_infos.formsemestre_id
@ -365,7 +475,7 @@ def SignaleAbsenceGrHebdo(
return "\n".join(H) return "\n".join(H)
@bp.route("/SignaleAbsenceGrSemestre") @bp.route("/SignaleAbsenceGrSemestre", methods=["GET", "POST"])
@permission_required(Permission.ScoAbsChange) @permission_required(Permission.ScoAbsChange)
@scodoc7func(context) @scodoc7func(context)
def SignaleAbsenceGrSemestre( def SignaleAbsenceGrSemestre(
@ -417,7 +527,7 @@ def SignaleAbsenceGrSemestre(
datedebut, datedebut,
datefin, datefin,
groups_infos.groups_query_args, groups_infos.groups_query_args,
urllib.quote(destination), six.moves.urllib.parse.quote(destination),
) )
) )
base_url = base_url_noweeks + "&nbweeks=%s" % nbweeks # sans le moduleimpl_id base_url = base_url_noweeks + "&nbweeks=%s" % nbweeks # sans le moduleimpl_id
@ -434,7 +544,7 @@ def SignaleAbsenceGrSemestre(
time.strftime("%d/%m/%Y", time.localtime()), time.strftime("%d/%m/%Y", time.localtime()),
work_saturday=work_saturday, work_saturday=work_saturday,
) )
today.next() today.next_day()
if jourfin > today: # ne propose jamais les semaines dans le futur if jourfin > today: # ne propose jamais les semaines dans le futur
jourfin = today jourfin = today
if jourdebut > today: if jourdebut > today:
@ -450,7 +560,7 @@ def SignaleAbsenceGrSemestre(
d = sco_abs.ddmmyyyy(datedebut, work_saturday=work_saturday) d = sco_abs.ddmmyyyy(datedebut, work_saturday=work_saturday)
while d <= jourfin: while d <= jourfin:
dates.append(d) dates.append(d)
d = d.next(7) # avance d'une semaine d = d.next_day(7) # avance d'une semaine
# #
msg = "Montrer seulement les 4 dernières semaines" msg = "Montrer seulement les 4 dernières semaines"
nwl = 4 nwl = 4
@ -713,7 +823,7 @@ def _gen_form_saisie_groupe(
H.append('<input type="hidden" name="dates" value="%s"/>' % ",".join(dates)) H.append('<input type="hidden" name="dates" value="%s"/>' % ",".join(dates))
H.append( H.append(
'<input type="hidden" name="destination" value="%s"/>' '<input type="hidden" name="destination" value="%s"/>'
% urllib.quote(destination) % six.moves.urllib.parse.quote(destination)
) )
# #
# version pour formulaire avec AJAX (Yann LB) # version pour formulaire avec AJAX (Yann LB)