Pages saisies absence + refonte tableau bord semestre. Close #342

This commit is contained in:
Emmanuel Viennet 2022-04-08 16:36:56 +02:00
parent 1153bc9a7c
commit a9f0fcdd6d
10 changed files with 94 additions and 95 deletions

View File

@ -74,6 +74,10 @@ class GroupDescr(db.Model):
f"""<{self.__class__.__name__} {self.id} "{self.group_name or '(tous)'}">""" f"""<{self.__class__.__name__} {self.id} "{self.group_name or '(tous)'}">"""
) )
def get_nom_with_part(self) -> str:
"Nom avec partition: 'TD A'"
return f"{self.partition.partition_name or ''} {self.group_name or '-'}"
group_membership = db.Table( group_membership = db.Table(
"group_membership", "group_membership",

View File

@ -86,9 +86,9 @@ def sidebar():
f"""<div class="sidebar"> f"""<div class="sidebar">
{ sidebar_common() } { sidebar_common() }
<div class="box-chercheetud">Chercher étudiant:<br/> <div class="box-chercheetud">Chercher étudiant:<br/>
<form method="get" id="form-chercheetud" <form method="get" id="form-chercheetud"
action="{ url_for('scolar.search_etud_in_dept', scodoc_dept=g.scodoc_dept) }"> action="{url_for('scolar.search_etud_in_dept', scodoc_dept=g.scodoc_dept) }">
<div><input type="text" size="12" id="in-expnom" name="expnom" spellcheck="false"></input></div> <div><input type="text" size="12" class="in-expnom" name="expnom" spellcheck="false"></input></div>
</form></div> </form></div>
<div class="etud-insidebar"> <div class="etud-insidebar">
""" """

View File

@ -31,9 +31,7 @@
import calendar import calendar
import datetime import datetime
import html import html
import string
import time import time
import types
from app.scodoc import notesdb as ndb from app.scodoc import notesdb as ndb
from app import log from app import log
@ -42,9 +40,9 @@ from app.scodoc.sco_exceptions import ScoValueError, ScoInvalidDateError
from app.scodoc import sco_abs_notification from app.scodoc import sco_abs_notification
from app.scodoc import sco_cache from app.scodoc import sco_cache
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
import app.scodoc.sco_utils as scu
# --- Misc tools.... ------------------ # --- Misc tools.... ------------------
@ -247,9 +245,9 @@ def day_names():
If work_saturday property is set, include saturday If work_saturday property is set, include saturday
""" """
if is_work_saturday(): if is_work_saturday():
return ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"] return scu.DAY_NAMES[:-1]
else: else:
return ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi"] return scu.DAY_NAMES[:-2]
def next_iso_day(date): def next_iso_day(date):

View File

@ -53,12 +53,10 @@ def form_search_etud(
): ):
"form recherche par nom" "form recherche par nom"
H = [] H = []
if title:
H.append("<h2>%s</h2>" % title)
H.append( H.append(
f"""<form action="{ url_for("scolar.search_etud_in_dept", scodoc_dept=g.scodoc_dept) }" method="POST"> f"""<form action="{ url_for("scolar.search_etud_in_dept", scodoc_dept=g.scodoc_dept) }" method="POST">
<b>{title}</b> <b>{title}</b>
<input type="text" name="expnom" width="12" spellcheck="false" value=""> <input type="text" name="expnom" class="in-expnom" width="12" spellcheck="false" value="">
<input type="submit" value="Chercher"> <input type="submit" value="Chercher">
<br/>(entrer une partie du nom) <br/>(entrer une partie du nom)
""" """

View File

@ -761,22 +761,29 @@ def _make_listes_sem(sem, with_absences=True):
if with_absences: if with_absences:
first_monday = sco_abs.ddmmyyyy(sem["date_debut"]).prev_monday() first_monday = sco_abs.ddmmyyyy(sem["date_debut"]).prev_monday()
form_abs_tmpl = f""" form_abs_tmpl = f"""
<td><form action="{url_for( <td>
<a href="%(url_etat)s">absences</a>
</td>
<td>
<form action="{url_for(
"absences.SignaleAbsenceGrSemestre", scodoc_dept=g.scodoc_dept "absences.SignaleAbsenceGrSemestre", scodoc_dept=g.scodoc_dept
)}" method="get"> )}" method="get">
<input type="hidden" name="datefin" value="{sem['date_fin']}"/> <input type="hidden" name="datefin" value="{sem['date_fin']}"/>
<input type="hidden" name="group_ids" value="%(group_id)s"/> <input type="hidden" name="group_ids" value="%(group_id)s"/>
<input type="hidden" name="destination" value="{destination}"/> <input type="hidden" name="destination" value="{destination}"/>
<input type="submit" value="Saisir absences du" /> <input type="submit" value="Saisir abs des" />
<select name="datedebut" class="noprint"> <select name="datedebut" class="noprint">
""" """
date = first_monday date = first_monday
for jour in sco_abs.day_names(): for jour in sco_abs.day_names():
form_abs_tmpl += '<option value="%s">%s</option>' % (date, jour) form_abs_tmpl += f'<option value="{date}">{jour}s</option>'
date = date.next_day() date = date.next_day()
form_abs_tmpl += """ form_abs_tmpl += f"""
</select> </select>
<a href="%(url_etat)s">état</a>
<a href="{
url_for("absences.choix_semaine", scodoc_dept=g.scodoc_dept)
}?group_id=%(group_id)s">saisie par semaine</a>
</form></td> </form></td>
""" """
else: else:
@ -788,7 +795,7 @@ def _make_listes_sem(sem, with_absences=True):
# Genere liste pour chaque partition (categorie de groupes) # Genere liste pour chaque partition (categorie de groupes)
for partition in sco_groups.get_partitions_list(sem["formsemestre_id"]): for partition in sco_groups.get_partitions_list(sem["formsemestre_id"]):
if not partition["partition_name"]: if not partition["partition_name"]:
H.append("<h4>Tous les étudiants</h4>" % partition) H.append("<h4>Tous les étudiants</h4>")
else: else:
H.append("<h4>Groupes de %(partition_name)s</h4>" % partition) H.append("<h4>Groupes de %(partition_name)s</h4>" % partition)
groups = sco_groups.get_partition_groups(partition) groups = sco_groups.get_partition_groups(partition)
@ -818,20 +825,6 @@ def _make_listes_sem(sem, with_absences=True):
) )
}">{group["label"]}</a> }">{group["label"]}</a>
</td><td> </td><td>
(<a href="{
url_for("scolar.groups_view",
group_ids=group["group_id"],
format="xls",
scodoc_dept=g.scodoc_dept,
)
}">tableur</a>)
<a href="{
url_for("scolar.groups_view",
curtab="tab-photos",
group_ids=group["group_id"],
scodoc_dept=g.scodoc_dept,
)
}">Photos</a>
</td> </td>
<td>({n_members} étudiants)</td> <td>({n_members} étudiants)</td>
""" """

View File

@ -178,6 +178,7 @@ MONTH_NAMES = (
"novembre", "novembre",
"décembre", "décembre",
) )
DAY_NAMES = ("lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche")
def fmt_note(val, note_max=None, keep_numeric=False): def fmt_note(val, note_max=None, keep_numeric=False):

View File

@ -3,14 +3,14 @@
$(function () { $(function () {
// Autocomplete recherche etudiants par nom // Autocomplete recherche etudiants par nom
$("#in-expnom").autocomplete( $(".in-expnom").autocomplete(
{ {
delay: 300, // wait 300ms before suggestions delay: 300, // wait 300ms before suggestions
minLength: 2, // min nb of chars before suggest minLength: 2, // min nb of chars before suggest
position: { collision: 'flip' }, // automatic menu position up/down position: { collision: 'flip' }, // automatic menu position up/down
source: "search_etud_by_name", source: SCO_URL + "/search_etud_by_name",
select: function (event, ui) { select: function (event, ui) {
$("#in-expnom").val(ui.item.value); $(".in-expnom").val(ui.item.value);
$("#form-chercheetud").submit(); $("#form-chercheetud").submit();
} }
}); });

View File

@ -15,7 +15,7 @@
<h2 class="insidebar">Dépt. {{ sco.prefs["DeptName"] }}</h2> <h2 class="insidebar">Dépt. {{ sco.prefs["DeptName"] }}</h2>
<a href="{{ url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}" class="sidebar">Accueil</a> <br /> <a href="{{ url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}" class="sidebar">Accueil</a> <br />
{% if sco.prefs["DeptIntranetURL"] %} {% if sco.prefs["DeptIntranetURL"] %}
<a href="{{ sco.prefs["DeptIntranetURL"] }}" class="sidebar"> <a href="{{ sco.prefs[" DeptIntranetURL"] }}" class="sidebar">
{{ sco.prefs["DeptIntranetTitle"] }}</a> {{ sco.prefs["DeptIntranetTitle"] }}</a>
{% endif %} {% endif %}
<br> <br>
@ -41,7 +41,7 @@
<form method="get" id="form-chercheetud" <form method="get" id="form-chercheetud"
action="{{ url_for('scolar.search_etud_in_dept', scodoc_dept=g.scodoc_dept) }}"> action="{{ url_for('scolar.search_etud_in_dept', scodoc_dept=g.scodoc_dept) }}">
<div> <div>
<input type="text" size="12" id="in-expnom" name="expnom" spellcheck="false" /> <input type="text" size="12" class="in-expnom" name="expnom" spellcheck="false" />
</div> </div>
</form> </form>
</div> </div>
@ -49,7 +49,7 @@
<div class="etud-insidebar"> <div class="etud-insidebar">
{% if sco.etud %} {% if sco.etud %}
<h2 id="insidebar-etud"><a href="{{url_for( <h2 id="insidebar-etud"><a href="{{url_for(
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=sco.etud.id )}}" class="sidebar"> 'scolar.ficheEtud', scodoc_dept=g.scodoc_dept, etudid=sco.etud.id )}}" class="sidebar">
<span class="fontred">{{sco.etud.nomprenom}}</span></a> <span class="fontred">{{sco.etud.nomprenom}}</span></a>
</h2> </h2>
<b>Absences</b> <b>Absences</b>

View File

@ -69,7 +69,7 @@ from app.decorators import (
permission_required, permission_required,
permission_required_compat_scodoc7, permission_required_compat_scodoc7,
) )
from app.models import FormSemestre from app.models import FormSemestre, GroupDescr
from app.models.absences import BilletAbsence from app.models.absences import BilletAbsence
from app.views import absences_bp as bp from app.views import absences_bp as bp
@ -119,63 +119,71 @@ def sco_publish(route, function, permission, methods=["GET"]):
@scodoc7func @scodoc7func
def index_html(): def index_html():
"""Gestionnaire absences, page principale""" """Gestionnaire absences, page principale"""
# crude portage from 1999 DTML
sems = sco_formsemestre.do_formsemestre_list()
authuser = current_user
H = [ H = [
html_sco_header.sco_header( html_sco_header.sco_header(
page_title="Gestion des absences", page_title="Saisie des absences",
cssstyles=["css/calabs.css"], cssstyles=["css/calabs.css"],
javascripts=["js/calabs.js"], javascripts=["js/calabs.js"],
), ),
"""<h2>Gestion des Absences</h2>""", """<h2>Traitement des absences</h2>
<p class="help">
Pour saisir des absences ou consulter les états, il est recommandé par passer par
le semestre concerné (saisie par jours nommés ou par semaines).
</p>
""",
] ]
if not sems: H.append(
"""<p class="help">Pour signaler, annuler ou justifier une absence pour un seul étudiant,
choisissez d'abord concerné:</p>"""
)
H.append(sco_find_etud.form_search_etud())
if current_user.has_permission(
Permission.ScoAbsChange
) and sco_preferences.get_preference("handle_billets_abs"):
H.append( 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("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())
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.base_url, <h2 style="margin-top: 30px;">Billets d'absence</h2>
sco_abs_views.formChoixSemestreGroupe(), <ul><li><a href="listeBillets">Traitement des billets d'absence en attente</a></li></ul>
"</p>", """
cal_select_week(), )
"""<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()) H.append(html_sco_header.sco_footer())
return "\n".join(H) return "\n".join(H)
@bp.route("/choix_semaine")
@scodoc
@permission_required(Permission.ScoAbsChange)
@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)
H = [
html_sco_header.sco_header(
page_title="Saisie des absences",
cssstyles=["css/calabs.css"],
javascripts=["js/calabs.js"],
),
f"""
<h2>Saisie des Absences</h2>
<form action="SignaleAbsenceGrHebdo" id="formw">
<p>
<span style="font-weight: bold; font-size:120%;">
Saisie par semaine </span> - Groupe: {group.get_nom_with_part()}
<input name="datelundi" type="hidden" value="x"/>
<input name="group_ids" type="hidden" value="{group_id}"/>
</p>
""",
cal_select_week(),
"""<p class="help">Sélectionner le groupe d'étudiants, puis cliquez sur une semaine pour
saisir les absences de toute cette semaine.</p>
</form>
""",
html_sco_header.sco_footer(),
]
return "\n".join(H)
def cal_select_week(year=None): def cal_select_week(year=None):
"display calendar allowing week selection" "display calendar allowing week selection"
if not year: if not year:
@ -479,7 +487,7 @@ def SignaleAbsenceGrSemestre(
datedebut, datedebut,
datefin, datefin,
destination="", destination="",
group_ids=[], # list of groups to display group_ids=(), # list of groups to display
nbweeks=4, # ne montre que les nbweeks dernieres semaines nbweeks=4, # ne montre que les nbweeks dernieres semaines
moduleimpl_id=None, moduleimpl_id=None,
): ):
@ -566,7 +574,7 @@ def SignaleAbsenceGrSemestre(
url_link_semaines += "&moduleimpl_id=" + str(moduleimpl_id) url_link_semaines += "&moduleimpl_id=" + str(moduleimpl_id)
# #
dates = [x.ISO() for x in dates] dates = [x.ISO() for x in dates]
dayname = sco_abs.day_names()[jourdebut.weekday] day_name = sco_abs.day_names()[jourdebut.weekday]
if groups_infos.tous_les_etuds_du_sem: if groups_infos.tous_les_etuds_du_sem:
gr_tit = "en" gr_tit = "en"
@ -579,19 +587,18 @@ def SignaleAbsenceGrSemestre(
H = [ H = [
html_sco_header.sco_header( html_sco_header.sco_header(
page_title="Saisie des absences", page_title=f"Saisie des absences du {day_name}",
init_qtip=True, init_qtip=True,
javascripts=["js/etud_info.js", "js/abs_ajax.js"], javascripts=["js/etud_info.js", "js/abs_ajax.js"],
no_side_bar=1, no_side_bar=1,
), ),
"""<table border="0" cellspacing="16"><tr><td> f"""<table border="0" cellspacing="16"><tr><td>
<h2>Saisie des absences %s %s, <h2>Saisie des absences {gr_tit} {sem["titre_num"]},
les <span class="fontred">%s</span></h2> les <span class="fontred">{day_name}s</span></h2>
<p> <p>
<a href="%s">%s</a> <a href="{url_link_semaines}">{msg}</a>
<form id="abs_form" action="doSignaleAbsenceGrSemestre" method="post"> <form id="abs_form" action="doSignaleAbsenceGrSemestre" method="post">
""" """,
% (gr_tit, sem["titre_num"], dayname, url_link_semaines, msg),
] ]
# #
if etuds: if etuds:
@ -820,7 +827,6 @@ def _gen_form_saisie_groupe(
# version pour formulaire avec AJAX (Yann LB) # version pour formulaire avec AJAX (Yann LB)
H.append( H.append(
""" """
<p><input type="button" value="Retour" onClick="window.location='%s'"/>
</p> </p>
</form> </form>
</p> </p>
@ -831,8 +837,7 @@ def _gen_form_saisie_groupe(
</p><p class="help">Si vous "décochez" une case, l'absence correspondante sera supprimée. </p><p class="help">Si vous "décochez" une case, l'absence correspondante sera supprimée.
Attention, les modifications sont automatiquement entregistrées au fur et à mesure. Attention, les modifications sont automatiquement entregistrées au fur et à mesure.
</p> </p>
""" """
% destination
) )
return H return H

View File

@ -1,7 +1,7 @@
# -*- mode: python -*- # -*- mode: python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
SCOVERSION = "9.1.92" SCOVERSION = "9.2.0a"
SCONAME = "ScoDoc" SCONAME = "ScoDoc"