forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -78,7 +78,11 @@ def compute_sem_moys_apc_using_ects(
|
|||||||
else:
|
else:
|
||||||
ects = ects_df.to_numpy()
|
ects = ects_df.to_numpy()
|
||||||
# ects est maintenant un array nb_etuds x nb_ues
|
# ects est maintenant un array nb_etuds x nb_ues
|
||||||
|
|
||||||
moy_gen = (etud_moy_ue_df * ects).sum(axis=1) / ects.sum(axis=1)
|
moy_gen = (etud_moy_ue_df * ects).sum(axis=1) / ects.sum(axis=1)
|
||||||
|
except ZeroDivisionError:
|
||||||
|
# peut arriver si aucun module... on ignore
|
||||||
|
moy_gen = pd.Series(np.NaN, index=etud_moy_ue_df.index)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
if None in ects:
|
if None in ects:
|
||||||
formation = db.session.get(Formation, formation_id)
|
formation = db.session.get(Formation, formation_id)
|
||||||
|
@ -79,13 +79,15 @@ Adresses d'origine:
|
|||||||
to : {orig_to}
|
to : {orig_to}
|
||||||
cc : {orig_cc}
|
cc : {orig_cc}
|
||||||
bcc: {orig_bcc}
|
bcc: {orig_bcc}
|
||||||
---
|
---
|
||||||
\n\n"""
|
\n\n"""
|
||||||
+ msg.body
|
+ msg.body
|
||||||
)
|
)
|
||||||
|
|
||||||
current_app.logger.info(
|
current_app.logger.info(
|
||||||
f"""email sent to{' (mode test)' if email_test_mode_address else ''}: {msg.recipients}
|
f"""email sent to{
|
||||||
|
' (mode test)' if email_test_mode_address else ''
|
||||||
|
}: {msg.recipients}
|
||||||
from sender {msg.sender}
|
from sender {msg.sender}
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
@ -98,7 +100,8 @@ def get_from_addr(dept_acronym: str = None):
|
|||||||
"""L'adresse "from" à utiliser pour envoyer un mail
|
"""L'adresse "from" à utiliser pour envoyer un mail
|
||||||
|
|
||||||
Si le departement est spécifié, ou si l'attribut `g.scodoc_dept`existe,
|
Si le departement est spécifié, ou si l'attribut `g.scodoc_dept`existe,
|
||||||
prend le `email_from_addr` des préférences de ce département si ce champ est non vide.
|
prend le `email_from_addr` des préférences de ce département si ce champ
|
||||||
|
est non vide.
|
||||||
Sinon, utilise le paramètre global `email_from_addr`.
|
Sinon, utilise le paramètre global `email_from_addr`.
|
||||||
Sinon, la variable de config `SCODOC_MAIL_FROM`.
|
Sinon, la variable de config `SCODOC_MAIL_FROM`.
|
||||||
"""
|
"""
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import datetime
|
||||||
import html
|
import html
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
from flask import g, current_app, abort
|
||||||
import psycopg2
|
import psycopg2
|
||||||
import psycopg2.pool
|
import psycopg2.pool
|
||||||
import psycopg2.extras
|
import psycopg2.extras
|
||||||
|
|
||||||
from flask import g, current_app, abort
|
|
||||||
|
|
||||||
import app
|
|
||||||
import app.scodoc.sco_utils as scu
|
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.sco_exceptions import ScoException, ScoValueError, NoteProcessError
|
from app.scodoc.sco_exceptions import ScoException, ScoValueError, NoteProcessError
|
||||||
import datetime
|
|
||||||
|
|
||||||
quote_html = html.escape
|
quote_html = html.escape
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ def list_abs_in_range(
|
|||||||
Returns:
|
Returns:
|
||||||
List of absences
|
List of absences
|
||||||
"""
|
"""
|
||||||
if matin != None:
|
if matin is not None:
|
||||||
matin = _toboolean(matin)
|
matin = _toboolean(matin)
|
||||||
ismatin = " AND A.MATIN = %(matin)s "
|
ismatin = " AND A.MATIN = %(matin)s "
|
||||||
else:
|
else:
|
||||||
@ -387,7 +387,7 @@ def count_abs_just(etudid, debut, fin, matin=None, moduleimpl_id=None) -> int:
|
|||||||
Returns:
|
Returns:
|
||||||
An integer.
|
An integer.
|
||||||
"""
|
"""
|
||||||
if matin != None:
|
if matin is not None:
|
||||||
matin = _toboolean(matin)
|
matin = _toboolean(matin)
|
||||||
ismatin = " AND A.MATIN = %(matin)s "
|
ismatin = " AND A.MATIN = %(matin)s "
|
||||||
else:
|
else:
|
||||||
@ -482,7 +482,9 @@ def _get_abs_description(a, cursor=None):
|
|||||||
else:
|
else:
|
||||||
a["matin"] = False
|
a["matin"] = False
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""select * from absences where etudid=%(etudid)s and jour=%(jour)s and matin=%(matin)s order by entry_date desc""",
|
"""SELECT * FROM absences
|
||||||
|
WHERE etudid=%(etudid)s AND jour=%(jour)s AND matin=%(matin)s
|
||||||
|
ORDER BY entry_date desc""",
|
||||||
a,
|
a,
|
||||||
)
|
)
|
||||||
A = cursor.dictfetchall()
|
A = cursor.dictfetchall()
|
||||||
@ -517,9 +519,9 @@ def list_abs_jour(date, am=True, pm=True, is_abs=True, is_just=None):
|
|||||||
req = """SELECT DISTINCT etudid, jour, matin FROM ABSENCES A
|
req = """SELECT DISTINCT etudid, jour, matin FROM ABSENCES A
|
||||||
WHERE A.jour = %(date)s
|
WHERE A.jour = %(date)s
|
||||||
"""
|
"""
|
||||||
if is_abs != None:
|
if is_abs is not None:
|
||||||
req += " AND A.estabs = %(is_abs)s"
|
req += " AND A.estabs = %(is_abs)s"
|
||||||
if is_just != None:
|
if is_just is not None:
|
||||||
req += " AND A.estjust = %(is_just)s"
|
req += " AND A.estjust = %(is_just)s"
|
||||||
if not am:
|
if not am:
|
||||||
req += " AND NOT matin "
|
req += " AND NOT matin "
|
||||||
@ -883,7 +885,7 @@ def MonthTableBody(
|
|||||||
descr = ev[4]
|
descr = ev[4]
|
||||||
#
|
#
|
||||||
cc = []
|
cc = []
|
||||||
if color != None:
|
if color is not None:
|
||||||
cc.append('<td bgcolor="%s" class="calcell">' % color)
|
cc.append('<td bgcolor="%s" class="calcell">' % color)
|
||||||
else:
|
else:
|
||||||
cc.append('<td class="calcell">')
|
cc.append('<td class="calcell">')
|
||||||
@ -896,7 +898,7 @@ def MonthTableBody(
|
|||||||
cc.append("<a %s %s>" % (href, descr))
|
cc.append("<a %s %s>" % (href, descr))
|
||||||
|
|
||||||
if legend or d == 1:
|
if legend or d == 1:
|
||||||
if pad_width != None:
|
if pad_width is not None:
|
||||||
n = pad_width - len(legend) # pad to 8 cars
|
n = pad_width - len(legend) # pad to 8 cars
|
||||||
if n > 0:
|
if n > 0:
|
||||||
legend = (
|
legend = (
|
||||||
@ -959,7 +961,7 @@ def MonthTableBody(
|
|||||||
ev_year = int(ev[0][:4])
|
ev_year = int(ev[0][:4])
|
||||||
ev_month = int(ev[0][5:7])
|
ev_month = int(ev[0][5:7])
|
||||||
ev_day = int(ev[0][8:10])
|
ev_day = int(ev[0][8:10])
|
||||||
if ev[4] != None:
|
if ev[4] is not None:
|
||||||
ev_half = int(ev[4])
|
ev_half = int(ev[4])
|
||||||
else:
|
else:
|
||||||
ev_half = 0
|
ev_half = 0
|
||||||
@ -978,7 +980,7 @@ def MonthTableBody(
|
|||||||
if len(ev) > 5 and ev[5]:
|
if len(ev) > 5 and ev[5]:
|
||||||
descr = ev[5]
|
descr = ev[5]
|
||||||
#
|
#
|
||||||
if color != None:
|
if color is not None:
|
||||||
cc.append('<td bgcolor="%s" class="calcell">' % (color))
|
cc.append('<td bgcolor="%s" class="calcell">' % (color))
|
||||||
else:
|
else:
|
||||||
cc.append('<td class="calcell">')
|
cc.append('<td class="calcell">')
|
||||||
@ -1072,7 +1074,8 @@ def invalidate_abs_count_sem(sem):
|
|||||||
|
|
||||||
|
|
||||||
def invalidate_abs_etud_date(etudid, date): # was invalidateAbsEtudDate
|
def invalidate_abs_etud_date(etudid, date): # was invalidateAbsEtudDate
|
||||||
"""Doit etre appelé à chaque modification des absences pour cet étudiant et cette date.
|
"""Doit etre appelé à chaque modification des absences
|
||||||
|
pour cet étudiant et cette date.
|
||||||
Invalide cache absence et caches semestre
|
Invalide cache absence et caches semestre
|
||||||
date: date au format ISO
|
date: date au format ISO
|
||||||
"""
|
"""
|
||||||
|
@ -137,14 +137,14 @@ def doSignaleAbsence(
|
|||||||
]
|
]
|
||||||
if dates:
|
if dates:
|
||||||
H.append(
|
H.append(
|
||||||
f"""<p>Ajout de {nbadded} absences <b>{just_str}justifiées</b>
|
f"""<p>Ajout de {nbadded} absences <b>{just_str}justifiées</b>
|
||||||
du {datedebut} au {datefin} {indication_module}
|
du {datedebut} au {datefin} {indication_module}
|
||||||
</p>
|
</p>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
H.append(
|
H.append(
|
||||||
f"""<p class="warning">Aucune date ouvrable
|
f"""<p class="warning">Aucune date ouvrable
|
||||||
entre le {datedebut} et le {datefin} !
|
entre le {datedebut} et le {datefin} !
|
||||||
</p>
|
</p>
|
||||||
"""
|
"""
|
||||||
@ -152,11 +152,11 @@ def doSignaleAbsence(
|
|||||||
|
|
||||||
H.append(
|
H.append(
|
||||||
f"""<ul>
|
f"""<ul>
|
||||||
<li><a class="stdlink" href="{url_for("absences.SignaleAbsenceEtud",
|
<li><a class="stdlink" href="{url_for("absences.SignaleAbsenceEtud",
|
||||||
scodoc_dept=g.scodoc_dept, etudid=etud.id
|
scodoc_dept=g.scodoc_dept, etudid=etud.id
|
||||||
)}">Autre absence pour <b>{etud.nomprenom}</b></a>
|
)}">Autre absence pour <b>{etud.nomprenom}</b></a>
|
||||||
</li>
|
</li>
|
||||||
<li><a class="stdlink" href="{url_for("absences.CalAbs",
|
<li><a class="stdlink" href="{url_for("absences.CalAbs",
|
||||||
scodoc_dept=g.scodoc_dept, etudid=etud.id
|
scodoc_dept=g.scodoc_dept, etudid=etud.id
|
||||||
)}">Calendrier de ses absences</a>
|
)}">Calendrier de ses absences</a>
|
||||||
</li>
|
</li>
|
||||||
@ -180,8 +180,12 @@ def SignaleAbsenceEtud(): # etudid implied
|
|||||||
"abs_require_module"
|
"abs_require_module"
|
||||||
) # on utilise la pref globale car pas de sem courant
|
) # on utilise la pref globale car pas de sem courant
|
||||||
if require_module:
|
if require_module:
|
||||||
menu_module = """<div class="ue_warning">Pas inscrit dans un semestre courant,
|
menu_module = """<div class="ue_warning">Pas
|
||||||
et l'indication du module est requise. Donc pas de saisie d'absence possible !</div>"""
|
inscrit dans un semestre courant,
|
||||||
|
et l'indication du module est requise.
|
||||||
|
Donc pas de saisie d'absence possible !
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
disabled = True
|
disabled = True
|
||||||
else:
|
else:
|
||||||
menu_module = ""
|
menu_module = ""
|
||||||
@ -197,17 +201,17 @@ def SignaleAbsenceEtud(): # etudid implied
|
|||||||
menu_module = """
|
menu_module = """
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function form_enable_disable() {
|
function form_enable_disable() {
|
||||||
if ( $("select#sel_moduleimpl_id").val() == "" ) {
|
if ( $("select#sel_moduleimpl_id").val() == "" ) {
|
||||||
$("#butsubmit").prop("disabled", true);
|
$("#butsubmit").prop("disabled", true);
|
||||||
} else {
|
} else {
|
||||||
$("#butsubmit").prop("disabled", false);
|
$("#butsubmit").prop("disabled", false);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
form_enable_disable();
|
form_enable_disable();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<p>Module:
|
<p>Module:
|
||||||
<select id="sel_moduleimpl_id" name="moduleimpl_id"
|
<select id="sel_moduleimpl_id" name="moduleimpl_id"
|
||||||
onChange="form_enable_disable();">"""
|
onChange="form_enable_disable();">"""
|
||||||
else:
|
else:
|
||||||
@ -250,7 +254,10 @@ def SignaleAbsenceEtud(): # etudid implied
|
|||||||
<p>
|
<p>
|
||||||
<table><tr>
|
<table><tr>
|
||||||
<td>Date début : </td>
|
<td>Date début : </td>
|
||||||
<td><input type="text" name="datedebut" size="10" class="datepicker"/> <em>j/m/a</em></td>
|
<td>
|
||||||
|
<input type="text" name="datedebut" size="10" class="datepicker"/>
|
||||||
|
<em>j/m/a</em>
|
||||||
|
</td>
|
||||||
<td> Date fin (optionnelle):</td>
|
<td> Date fin (optionnelle):</td>
|
||||||
<td><input type="text" name="datefin" size="10" class="datepicker"/> <em>j/m/a</em></td>
|
<td><input type="text" name="datefin" size="10" class="datepicker"/> <em>j/m/a</em></td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -269,14 +276,14 @@ Raison: <input type="text" name="description" size="42"/> (optionnel)
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<input id="butsubmit" type="submit" value="Envoyer" disable="%(disabled)s"/>
|
<input id="butsubmit" type="submit" value="Envoyer" disable="%(disabled)s"/>
|
||||||
<em>
|
<em>
|
||||||
<p>Seuls les modules du semestre en cours apparaissent.</p>
|
<p>Seuls les modules du semestre en cours apparaissent.</p>
|
||||||
<p>Évitez de saisir une absence pour un module qui n'est pas en place à cette date.</p>
|
<p>Évitez de saisir une absence pour un module qui n'est pas en place à cette date.</p>
|
||||||
<p>Toutes les dates sont au format jour/mois/annee.</p>
|
<p>Toutes les dates sont au format jour/mois/annee.</p>
|
||||||
</em>
|
</em>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
"""
|
"""
|
||||||
% {
|
% {
|
||||||
"etudid": etud["etudid"],
|
"etudid": etud["etudid"],
|
||||||
@ -354,7 +361,10 @@ def doJustifAbsence(
|
|||||||
)
|
)
|
||||||
|
|
||||||
H.append(
|
H.append(
|
||||||
"""<ul><li><a href="JustifAbsenceEtud?etudid=%(etudid)s">Autre justification pour <b>%(nomprenom)s</b></a></li>
|
"""<ul>
|
||||||
|
<li><a href="JustifAbsenceEtud?etudid=%(etudid)s">Autre justification
|
||||||
|
pour <b>%(nomprenom)s</b>
|
||||||
|
</a></li>
|
||||||
<li><a href="SignaleAbsenceEtud?etudid=%(etudid)s">Signaler une absence</a></li>
|
<li><a href="SignaleAbsenceEtud?etudid=%(etudid)s">Signaler une absence</a></li>
|
||||||
<li><a href="CalAbs?etudid=%(etudid)s">Calendrier de ses absences</a></li>
|
<li><a href="CalAbs?etudid=%(etudid)s">Calendrier de ses absences</a></li>
|
||||||
<li><a href="ListeAbsEtud?etudid=%(etudid)s">Liste de ses absences</a></li>
|
<li><a href="ListeAbsEtud?etudid=%(etudid)s">Liste de ses absences</a></li>
|
||||||
@ -389,12 +399,12 @@ def JustifAbsenceEtud(): # etudid implied
|
|||||||
),
|
),
|
||||||
"""</a></td></tr></table>""",
|
"""</a></td></tr></table>""",
|
||||||
"""
|
"""
|
||||||
<form action="doJustifAbsence" method="get">
|
<form action="doJustifAbsence" method="get">
|
||||||
<input type="hidden" name="etudid" value="%(etudid)s">
|
<input type="hidden" name="etudid" value="%(etudid)s">
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<table><tr>
|
<table><tr>
|
||||||
<td>Date début : </td>
|
<td>Date début : </td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="datedebut" size="10" class="datepicker"/>
|
<input type="text" name="datedebut" size="10" class="datepicker"/>
|
||||||
</td>
|
</td>
|
||||||
@ -412,7 +422,7 @@ def JustifAbsenceEtud(): # etudid implied
|
|||||||
Raison: <input type="text" name="description" size="42"/> (optionnel)
|
Raison: <input type="text" name="description" size="42"/> (optionnel)
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<input type="submit" value="Envoyer">
|
<input type="submit" value="Envoyer">
|
||||||
|
|
||||||
</form> """
|
</form> """
|
||||||
% etud,
|
% etud,
|
||||||
@ -458,8 +468,10 @@ def doAnnuleAbsence(datedebut, datefin, demijournee, etudid=False): # etudid im
|
|||||||
H.append(
|
H.append(
|
||||||
"""<ul><li><a href="AnnuleAbsenceEtud?etudid=%(etudid)s">Annulation d'une
|
"""<ul><li><a href="AnnuleAbsenceEtud?etudid=%(etudid)s">Annulation d'une
|
||||||
autre absence pour <b>%(nomprenom)s</b></a></li>
|
autre absence pour <b>%(nomprenom)s</b></a></li>
|
||||||
<li><a href="SignaleAbsenceEtud?etudid=%(etudid)s">Ajout d'une absence</a></li>
|
<li><a href="SignaleAbsenceEtud?etudid=%(etudid)s">Ajout d'une
|
||||||
<li><a href="CalAbs?etudid=%(etudid)s">Calendrier de ses absences</a></li>
|
absence</a></li>
|
||||||
|
<li><a href="CalAbs?etudid=%(etudid)s">Calendrier de ses
|
||||||
|
absences</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr>"""
|
<hr>"""
|
||||||
% etud
|
% etud
|
||||||
@ -480,10 +492,11 @@ def AnnuleAbsenceEtud(): # etudid implied
|
|||||||
page_title="Annulation d'une absence pour %(nomprenom)s" % etud,
|
page_title="Annulation d'une absence pour %(nomprenom)s" % etud,
|
||||||
),
|
),
|
||||||
"""<table><tr><td>
|
"""<table><tr><td>
|
||||||
<h2><font color="#FF0000">Annulation</font> d'une absence pour %(nomprenom)s</h2>
|
<h2><font color="#FF0000">Annulation</font> d'une absence
|
||||||
|
pour %(nomprenom)s</h2>
|
||||||
</td><td>
|
</td><td>
|
||||||
"""
|
"""
|
||||||
% etud, # "
|
% etud,
|
||||||
"""<a href="%s">"""
|
"""<a href="%s">"""
|
||||||
% url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid),
|
% url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid),
|
||||||
sco_photos.etud_photo_html(
|
sco_photos.etud_photo_html(
|
||||||
@ -491,16 +504,19 @@ def AnnuleAbsenceEtud(): # etudid implied
|
|||||||
title="fiche de " + etud["nomprenom"],
|
title="fiche de " + etud["nomprenom"],
|
||||||
),
|
),
|
||||||
"""</a></td></tr></table>""",
|
"""</a></td></tr></table>""",
|
||||||
"""<p>A n'utiliser que suite à une erreur de saisie ou lorsqu'il s'avère que l'étudiant était en fait présent. </p>
|
"""<p>A n'utiliser que suite à une erreur de saisie ou lorsqu'il s'avère que
|
||||||
<p><font color="#FF0000">Si plusieurs modules sont affectés, les absences seront toutes effacées. </font></p>
|
l'étudiant était en fait présent.
|
||||||
"""
|
</p>
|
||||||
|
<p><font color="#FF0000">Si plusieurs modules sont affectés,
|
||||||
|
les absences seront toutes effacées. </font></p>
|
||||||
|
"""
|
||||||
% etud,
|
% etud,
|
||||||
"""<table frame="border" border="1"><tr><td>
|
"""<table frame="border" border="1"><tr><td>
|
||||||
<form action="doAnnuleAbsence" method="get">
|
<form action="doAnnuleAbsence" method="get">
|
||||||
<input type="hidden" name="etudid" value="%(etudid)s">
|
<input type="hidden" name="etudid" value="%(etudid)s">
|
||||||
<p>
|
<p>
|
||||||
<table><tr>
|
<table><tr>
|
||||||
<td>Date début : </td>
|
<td>Date début : </td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="datedebut" size="10" class="datepicker"/> <em>j/m/a</em>
|
<input type="text" name="datedebut" size="10" class="datepicker"/> <em>j/m/a</em>
|
||||||
</td>
|
</td>
|
||||||
@ -511,22 +527,22 @@ def AnnuleAbsenceEtud(): # etudid implied
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<input type="radio" name="demijournee" value="2" checked>journée(s)
|
<input type="radio" name="demijournee" value="2" checked>journée(s)
|
||||||
<input type="radio" name="demijournee" value="1">Matin(s)
|
<input type="radio" name="demijournee" value="1">Matin(s)
|
||||||
<input type="radio" name="demijournee" value="0">Après midi
|
<input type="radio" name="demijournee" value="0">Après midi
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<input type="submit" value="Supprimer les absences">
|
<input type="submit" value="Supprimer les absences">
|
||||||
</form>
|
</form>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
|
|
||||||
<tr><td>
|
<tr><td>
|
||||||
<form action="doAnnuleJustif" method="get">
|
<form action="doAnnuleJustif" method="get">
|
||||||
<input type="hidden" name="etudid" value="%(etudid)s">
|
<input type="hidden" name="etudid" value="%(etudid)s">
|
||||||
<p>
|
<p>
|
||||||
<table><tr>
|
<table><tr>
|
||||||
<td>Date début : </td>
|
<td>Date début : </td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="datedebut0" size="10" class="datepicker"/> <em>j/m/a</em>
|
<input type="text" name="datedebut0" size="10" class="datepicker"/> <em>j/m/a</em>
|
||||||
</td>
|
</td>
|
||||||
@ -538,15 +554,16 @@ def AnnuleAbsenceEtud(): # etudid implied
|
|||||||
</table>
|
</table>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
<input type="radio" name="demijournee" value="2" checked>journée(s)
|
<input type="radio" name="demijournee" value="2" checked>journée(s)
|
||||||
<input type="radio" name="demijournee" value="1">Matin(s)
|
<input type="radio" name="demijournee" value="1">Matin(s)
|
||||||
<input type="radio" name="demijournee" value="0">Après midi
|
<input type="radio" name="demijournee" value="0">Après midi
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<input type="submit" value="Supprimer les justificatifs">
|
<input type="submit" value="Supprimer les justificatifs">
|
||||||
<i>(utiliser ceci en cas de justificatif erroné saisi indépendemment d'une absence)</i>
|
<i>(utiliser ceci en cas de justificatif erroné saisi indépendemment
|
||||||
</form>
|
d'une absence)</i>
|
||||||
|
</form>
|
||||||
</td></tr></table>"""
|
</td></tr></table>"""
|
||||||
% etud,
|
% etud,
|
||||||
html_sco_header.sco_footer(),
|
html_sco_header.sco_footer(),
|
||||||
@ -591,8 +608,10 @@ def doAnnuleJustif(datedebut0, datefin0, demijournee): # etudid implied
|
|||||||
H.append(
|
H.append(
|
||||||
"""<ul><li><a href="AnnuleAbsenceEtud?etudid=%(etudid)s">Annulation d'une
|
"""<ul><li><a href="AnnuleAbsenceEtud?etudid=%(etudid)s">Annulation d'une
|
||||||
autre absence pour <b>%(nomprenom)s</b></a></li>
|
autre absence pour <b>%(nomprenom)s</b></a></li>
|
||||||
<li><a href="SignaleAbsenceEtud?etudid=%(etudid)s">Ajout d'une absence</a></li>
|
<li><a href="SignaleAbsenceEtud?etudid=%(etudid)s">Ajout d'une
|
||||||
<li><a href="CalAbs?etudid=%(etudid)s">Calendrier de ses absences</a></li>
|
absence</a></li>
|
||||||
|
<li><a href="CalAbs?etudid=%(etudid)s">Calendrier de ses
|
||||||
|
absences</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr>"""
|
<hr>"""
|
||||||
% etud
|
% etud
|
||||||
@ -634,8 +653,11 @@ def AnnuleAbsencesDatesNoJust(etudid, dates, moduleimpl_id=None):
|
|||||||
# supr les absences non justifiees
|
# supr les absences non justifiees
|
||||||
for date in dates:
|
for date in dates:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""DELETE FROM absences
|
"""DELETE FROM absences
|
||||||
WHERE etudid=%(etudid)s and (not estjust) and jour=%(date)s and moduleimpl_id=%(moduleimpl_id)s
|
WHERE etudid=%(etudid)s
|
||||||
|
AND (not estjust)
|
||||||
|
AND jour=%(date)s
|
||||||
|
AND moduleimpl_id=%(moduleimpl_id)s
|
||||||
""",
|
""",
|
||||||
vars(),
|
vars(),
|
||||||
)
|
)
|
||||||
@ -643,8 +665,11 @@ def AnnuleAbsencesDatesNoJust(etudid, dates, moduleimpl_id=None):
|
|||||||
# s'assure que les justificatifs ne sont pas "absents"
|
# s'assure que les justificatifs ne sont pas "absents"
|
||||||
for date in dates:
|
for date in dates:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""UPDATE absences SET estabs=FALSE
|
"""UPDATE absences
|
||||||
WHERE etudid=%(etudid)s AND jour=%(date)s AND moduleimpl_id=%(moduleimpl_id)s
|
SET estabs=FALSE
|
||||||
|
WHERE etudid=%(etudid)s
|
||||||
|
AND jour=%(date)s
|
||||||
|
AND moduleimpl_id=%(moduleimpl_id)s
|
||||||
""",
|
""",
|
||||||
vars(),
|
vars(),
|
||||||
)
|
)
|
||||||
@ -724,7 +749,7 @@ def _convert_sco_year(year) -> int:
|
|||||||
year = int(year)
|
year = int(year)
|
||||||
if year > 1900 and year < 2999:
|
if year > 1900 and year < 2999:
|
||||||
return year
|
return year
|
||||||
except:
|
except ValueError:
|
||||||
raise ScoValueError("année scolaire invalide")
|
raise ScoValueError("année scolaire invalide")
|
||||||
|
|
||||||
|
|
||||||
@ -771,7 +796,8 @@ def CalAbs(etudid, sco_year=None):
|
|||||||
"""<b><font color="#EE0000">A : absence NON justifiée</font><br>
|
"""<b><font color="#EE0000">A : absence NON justifiée</font><br>
|
||||||
<font color="#F8B7B0">a : absence justifiée</font><br>
|
<font color="#F8B7B0">a : absence justifiée</font><br>
|
||||||
<font color="#8EA2C6">X : justification sans absence</font><br>
|
<font color="#8EA2C6">X : justification sans absence</font><br>
|
||||||
%d absences sur l'année, dont %d justifiées (soit %d non justifiées)</b> <em>(%d justificatifs inutilisés)</em>
|
%d absences sur l'année, dont %d justifiées (soit %d non justifiées)</b>
|
||||||
|
<em>(%d justificatifs inutilisés)</em>
|
||||||
</p>
|
</p>
|
||||||
"""
|
"""
|
||||||
% (nbabs, nbabsjust, nbabs - nbabsjust, len(justifs_noabs)),
|
% (nbabs, nbabsjust, nbabs - nbabsjust, len(justifs_noabs)),
|
||||||
@ -790,7 +816,8 @@ def CalAbs(etudid, sco_year=None):
|
|||||||
"""<form method="GET" action="CalAbs" name="f">""",
|
"""<form method="GET" action="CalAbs" name="f">""",
|
||||||
"""<input type="hidden" name="etudid" value="%s"/>""" % etudid,
|
"""<input type="hidden" name="etudid" value="%s"/>""" % etudid,
|
||||||
"""Année scolaire %s-%s""" % (annee_scolaire, annee_scolaire + 1),
|
"""Année scolaire %s-%s""" % (annee_scolaire, annee_scolaire + 1),
|
||||||
""" Changer année: <select name="sco_year" onchange="document.f.submit()">""",
|
""" Changer année:
|
||||||
|
<select name="sco_year" onchange="document.f.submit()">""",
|
||||||
]
|
]
|
||||||
for y in range(annee_courante, min(annee_courante - 6, annee_scolaire - 6), -1):
|
for y in range(annee_courante, min(annee_courante - 6, annee_scolaire - 6), -1):
|
||||||
H.append("""<option value="%s" """ % y)
|
H.append("""<option value="%s" """ % y)
|
||||||
@ -819,7 +846,8 @@ def ListeAbsEtud(
|
|||||||
etudid:
|
etudid:
|
||||||
with_evals: indique les evaluations aux dates d'absences
|
with_evals: indique les evaluations aux dates d'absences
|
||||||
absjust_only: si vrai, renvoie table absences justifiées
|
absjust_only: si vrai, renvoie table absences justifiées
|
||||||
sco_year: année scolaire à utiliser. Si non spécifier, utilie l'année en cours. e.g. "2005"
|
sco_year: année scolaire à utiliser.
|
||||||
|
Si non spécifier, utilie l'année en cours. e.g. "2005"
|
||||||
"""
|
"""
|
||||||
# si absjust_only, table absjust seule (export xls ou pdf)
|
# si absjust_only, table absjust seule (export xls ou pdf)
|
||||||
absjust_only = scu.to_bool(absjust_only)
|
absjust_only = scu.to_bool(absjust_only)
|
||||||
@ -941,10 +969,12 @@ def _tables_abs_etud(
|
|||||||
for a in absnonjust + absjust:
|
for a in absnonjust + absjust:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""SELECT eval.*
|
"""SELECT eval.*
|
||||||
FROM notes_evaluation eval, notes_moduleimpl_inscription mi, notes_moduleimpl m
|
FROM notes_evaluation eval,
|
||||||
WHERE eval.jour = %(jour)s
|
notes_moduleimpl_inscription mi,
|
||||||
|
notes_moduleimpl m
|
||||||
|
WHERE eval.jour = %(jour)s
|
||||||
and eval.moduleimpl_id = m.id
|
and eval.moduleimpl_id = m.id
|
||||||
and mi.moduleimpl_id = m.id
|
and mi.moduleimpl_id = m.id
|
||||||
and mi.etudid = %(etudid)s
|
and mi.etudid = %(etudid)s
|
||||||
""",
|
""",
|
||||||
{"jour": a["jour"].strftime("%Y-%m-%d"), "etudid": etudid},
|
{"jour": a["jour"].strftime("%Y-%m-%d"), "etudid": etudid},
|
||||||
@ -984,9 +1014,10 @@ def _tables_abs_etud(
|
|||||||
)[0]
|
)[0]
|
||||||
if format == "html":
|
if format == "html":
|
||||||
ex.append(
|
ex.append(
|
||||||
f"""<a title="{mod['module']['titre']}" href="{url_for('notes.moduleimpl_status',
|
f"""<a title="{mod['module']['titre']}" href="{
|
||||||
scodoc_dept=g.scodoc_dept, moduleimpl_id=mod["moduleimpl_id"])}
|
url_for('notes.moduleimpl_status',
|
||||||
">{mod["module"]["code"] or "(module sans code)"}</a>"""
|
scodoc_dept=g.scodoc_dept, moduleimpl_id=mod["moduleimpl_id"])
|
||||||
|
}">{mod["module"]["code"] or "(module sans code)"}</a>"""
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
ex.append(mod["module"]["code"] or "(module sans code)")
|
ex.append(mod["module"]["code"] or "(module sans code)")
|
||||||
@ -1003,7 +1034,7 @@ def _tables_abs_etud(
|
|||||||
if format == "html":
|
if format == "html":
|
||||||
ex.append(
|
ex.append(
|
||||||
f"""<a title="{mod['module']['titre']}"
|
f"""<a title="{mod['module']['titre']}"
|
||||||
href="{url_for('notes.moduleimpl_status',
|
href="{url_for('notes.moduleimpl_status',
|
||||||
scodoc_dept=g.scodoc_dept, moduleimpl_id=mod["moduleimpl_id"])}
|
scodoc_dept=g.scodoc_dept, moduleimpl_id=mod["moduleimpl_id"])}
|
||||||
">{mod["module"]["code"] or '(module sans code)'}</a>"""
|
">{mod["module"]["code"] or '(module sans code)'}</a>"""
|
||||||
)
|
)
|
||||||
|
@ -321,9 +321,10 @@ def filter_by_formsemestre(
|
|||||||
def justifies(justi: Justificatif, obj: bool = False) -> list[int] or Query:
|
def justifies(justi: Justificatif, obj: bool = False) -> list[int] or Query:
|
||||||
"""
|
"""
|
||||||
Retourne la liste des assiduite_id qui sont justifié par la justification
|
Retourne la liste des assiduite_id qui sont justifié par la justification
|
||||||
Une assiduité est justifiée si elle est COMPLETEMENT ou PARTIELLEMENT comprise dans la plage du justificatif
|
Une assiduité est justifiée si elle est COMPLETEMENT ou PARTIELLEMENT
|
||||||
et que l'état du justificatif est "valide"
|
comprise dans la plage du justificatif
|
||||||
renvoie des id si obj == False, sinon les Assiduités
|
et que l'état du justificatif est "valide".
|
||||||
|
Renvoie des id si obj == False, sinon les Assiduités
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if justi.etat != scu.EtatJustificatif.VALIDE:
|
if justi.etat != scu.EtatJustificatif.VALIDE:
|
||||||
@ -427,7 +428,7 @@ def invalidate_assiduites_count(etudid, sem):
|
|||||||
"""Invalidate (clear) cached counts"""
|
"""Invalidate (clear) cached counts"""
|
||||||
date_debut = sem["date_debut_iso"]
|
date_debut = sem["date_debut_iso"]
|
||||||
date_fin = sem["date_fin_iso"]
|
date_fin = sem["date_fin_iso"]
|
||||||
for met in sco_preferences.ASSIDUITES_METRIC_LABEL.values():
|
for met in scu.AssiduitesMetrics.TAG:
|
||||||
key = str(etudid) + "_" + date_debut + "_" + date_fin + f"{met}_assiduites"
|
key = str(etudid) + "_" + date_debut + "_" + date_fin + f"{met}_assiduites"
|
||||||
sco_cache.AbsSemEtudCache.delete(key)
|
sco_cache.AbsSemEtudCache.delete(key)
|
||||||
|
|
||||||
@ -444,9 +445,9 @@ def invalidate_assiduites_count_sem(sem):
|
|||||||
|
|
||||||
|
|
||||||
def invalidate_assiduites_etud_date(etudid, date: datetime):
|
def invalidate_assiduites_etud_date(etudid, date: datetime):
|
||||||
"""Doit etre appelé à chaque modification des assiduites pour cet étudiant et cette date.
|
"""Doit etre appelé à chaque modification des assiduites
|
||||||
|
pour cet étudiant et cette date.
|
||||||
Invalide cache absence et caches semestre
|
Invalide cache absence et caches semestre
|
||||||
date: date au format ISO
|
|
||||||
"""
|
"""
|
||||||
from app.scodoc import sco_compute_moy
|
from app.scodoc import sco_compute_moy
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
|
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
if not etudid in nt.identdict:
|
if etudid not in nt.identdict:
|
||||||
abort(404, "etudiant non inscrit dans ce semestre")
|
abort(404, "etudiant non inscrit dans ce semestre")
|
||||||
d = {"type": "classic", "version": "0"}
|
d = {"type": "classic", "version": "0"}
|
||||||
if (not sem["bul_hide_xml"]) or force_publishing:
|
if (not sem["bul_hide_xml"]) or force_publishing:
|
||||||
|
@ -198,13 +198,6 @@ def _get_pref_default_value_from_config(name, pref_spec):
|
|||||||
|
|
||||||
_INSTALLED_FONTS = ", ".join(sco_pdf.get_available_font_names())
|
_INSTALLED_FONTS = ", ".join(sco_pdf.get_available_font_names())
|
||||||
|
|
||||||
ASSIDUITES_METRIC_LABEL = {
|
|
||||||
# l'ordre est important, c'est celui-du menu. Le defaut en 1er donc.
|
|
||||||
"1/2 J.": "demi",
|
|
||||||
"J.": "journee",
|
|
||||||
"H.": "heure",
|
|
||||||
}
|
|
||||||
|
|
||||||
PREF_CATEGORIES = (
|
PREF_CATEGORIES = (
|
||||||
# sur page "Paramètres"
|
# sur page "Paramètres"
|
||||||
("general", {"title": ""}), # voir paramètre titlr de TrivialFormulator
|
("general", {"title": ""}), # voir paramètre titlr de TrivialFormulator
|
||||||
@ -666,8 +659,8 @@ class BasePreferences(object):
|
|||||||
{
|
{
|
||||||
"initvalue": "1/2 J.",
|
"initvalue": "1/2 J.",
|
||||||
"input_type": "menu",
|
"input_type": "menu",
|
||||||
"labels": list(ASSIDUITES_METRIC_LABEL.keys()),
|
"labels": scu.AssiduitesMetrics.LONG,
|
||||||
"allowed_values": list(ASSIDUITES_METRIC_LABEL.keys()),
|
"allowed_values": scu.AssiduitesMetrics.SHORT,
|
||||||
"title": "Métrique de l'assiduité",
|
"title": "Métrique de l'assiduité",
|
||||||
"explanation": "Unité utilisée dans la fiche étudiante, les bilans et les calculs",
|
"explanation": "Unité utilisée dans la fiche étudiante, les bilans et les calculs",
|
||||||
"category": "assi",
|
"category": "assi",
|
||||||
|
@ -166,6 +166,11 @@ class BiDirectionalEnum(Enum):
|
|||||||
"""Vérifie sur un attribut existe dans l'enum"""
|
"""Vérifie sur un attribut existe dans l'enum"""
|
||||||
return attr.upper() in cls._member_names_
|
return attr.upper() in cls._member_names_
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def all(cls, keys=True):
|
||||||
|
"""Retourne toutes les clés de l'enum"""
|
||||||
|
return cls._member_names_ if keys else list(cls._value2member_map_.keys())
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get(cls, attr: str, default: any = None):
|
def get(cls, attr: str, default: any = None):
|
||||||
"""Récupère une valeur à partir de son attribut"""
|
"""Récupère une valeur à partir de son attribut"""
|
||||||
@ -254,15 +259,54 @@ def is_period_overlapping(
|
|||||||
return p_deb < i_fin and p_fin > i_deb
|
return p_deb < i_fin and p_fin > i_deb
|
||||||
|
|
||||||
|
|
||||||
def translate_assiduites_metric(hr_metric) -> str:
|
class AssiduitesMetrics:
|
||||||
if hr_metric == "1/2 J.":
|
"""Labels associés au métrique de l'assiduité"""
|
||||||
return "demi"
|
|
||||||
if hr_metric == "J.":
|
SHORT: list[str] = ["1/2 J.", "J.", "H."]
|
||||||
return "journee"
|
LONG: list[str] = ["Demi-journée", "Journée", "Heure"]
|
||||||
if hr_metric == "N.":
|
TAG: list[str] = ["demi", "journee", "heure"]
|
||||||
return "compte"
|
|
||||||
if hr_metric == "H.":
|
|
||||||
return "heure"
|
def translate_assiduites_metric(metric, inverse=True, short=True) -> str:
|
||||||
|
"""
|
||||||
|
translate_assiduites_metric
|
||||||
|
|
||||||
|
SHORT[true] : "J." "H." "N." "1/2 J."
|
||||||
|
SHORT[false] : "Journée" "Heure" "Nombre" "Demi-Journée"
|
||||||
|
|
||||||
|
inverse[false] : "demi" -> "1/2 J."
|
||||||
|
inverse[true] : "1/2 J." -> "demi"
|
||||||
|
|
||||||
|
|
||||||
|
Args:
|
||||||
|
metric (str): la métrique à traduire
|
||||||
|
inverse (bool, optional). Defaults to True.
|
||||||
|
short (bool, optional). Defaults to True.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: la métrique traduite
|
||||||
|
"""
|
||||||
|
index: int = None
|
||||||
|
if not inverse:
|
||||||
|
try:
|
||||||
|
index = AssiduitesMetrics.TAG.index(metric)
|
||||||
|
return (
|
||||||
|
AssiduitesMetrics.SHORT[index]
|
||||||
|
if short
|
||||||
|
else AssiduitesMetrics.LONG[index]
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
index = (
|
||||||
|
AssiduitesMetrics.SHORT.index(metric)
|
||||||
|
if short
|
||||||
|
else AssiduitesMetrics.LONG.index(metric)
|
||||||
|
)
|
||||||
|
return AssiduitesMetrics.TAG[index]
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
# Types de modules
|
# Types de modules
|
||||||
|
@ -125,8 +125,8 @@ class RowAssi(tb.Row):
|
|||||||
"absent": ["Absences", 0.0, 0.0],
|
"absent": ["Absences", 0.0, 0.0],
|
||||||
}
|
}
|
||||||
|
|
||||||
assi_metric = sco_preferences.ASSIDUITES_METRIC_LABEL.get(
|
assi_metric = scu.translate_assiduites_metric(
|
||||||
sco_preferences.get_preference("assi_metrique", dept_id=g.scodoc_dept_id)
|
sco_preferences.get_preference("assi_metrique", dept_id=g.scodoc_dept_id),
|
||||||
)
|
)
|
||||||
|
|
||||||
for etat, valeur in retour.items():
|
for etat, valeur in retour.items():
|
||||||
|
@ -336,19 +336,21 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
const defAnnee = {{ annee }}
|
const defAnnee = {{ annee }}
|
||||||
|
let annees = {{ annees | safe }}
|
||||||
|
annees = annees.filter((x, i) => annees.indexOf(x) === i)
|
||||||
const etudid = {{ sco.etud.id }};
|
const etudid = {{ sco.etud.id }};
|
||||||
const nonwork = [{{ nonworkdays | safe }}];
|
const nonwork = [{{ nonworkdays | safe }}];
|
||||||
window.onload = () => {
|
window.onload = () => {
|
||||||
const select = document.querySelector('#annee');
|
const select = document.querySelector('#annee');
|
||||||
for (let i = defAnnee + 1; i > defAnnee - 6; i--) {
|
annees.forEach((a) => {
|
||||||
const opt = document.createElement("option");
|
const opt = document.createElement("option");
|
||||||
opt.value = i + "",
|
opt.value = a + "",
|
||||||
opt.textContent = i + "";
|
opt.textContent = `${a} - ${a + 1}`;
|
||||||
if (i === defAnnee) {
|
if (a === defAnnee) {
|
||||||
opt.selected = true;
|
opt.selected = true;
|
||||||
}
|
}
|
||||||
select.appendChild(opt)
|
select.appendChild(opt)
|
||||||
}
|
})
|
||||||
setterAnnee(defAnnee)
|
setterAnnee(defAnnee)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,7 +162,11 @@
|
|||||||
userIdDiv.textContent = `saisi le ${formatDateModal(
|
userIdDiv.textContent = `saisi le ${formatDateModal(
|
||||||
assiduite.entry_date,
|
assiduite.entry_date,
|
||||||
"à"
|
"à"
|
||||||
)} \npar ${assiduite.user_id}`;
|
)}`;
|
||||||
|
|
||||||
|
if (assiduite.user_id != null) {
|
||||||
|
userIdDiv.textContent += `\npar ${assiduite.user_id}`
|
||||||
|
}
|
||||||
bubble.appendChild(userIdDiv);
|
bubble.appendChild(userIdDiv);
|
||||||
|
|
||||||
bubble.style.left = `${event.clientX - bubble.offsetWidth / 2}px`;
|
bubble.style.left = `${event.clientX - bubble.offsetWidth / 2}px`;
|
||||||
|
@ -327,8 +327,8 @@ def bilan_etud():
|
|||||||
date_debut: str = f"{scu.annee_scolaire()}-09-01"
|
date_debut: str = f"{scu.annee_scolaire()}-09-01"
|
||||||
date_fin: str = f"{scu.annee_scolaire()+1}-06-30"
|
date_fin: str = f"{scu.annee_scolaire()+1}-06-30"
|
||||||
|
|
||||||
assi_metric = sco_preferences.ASSIDUITES_METRIC_LABEL.get(
|
assi_metric = scu.translate_assiduites_metric(
|
||||||
sco_preferences.get_preference("assi_metrique", dept_id=g.scodoc_dept_id)
|
sco_preferences.get_preference("assi_metrique", dept_id=g.scodoc_dept_id),
|
||||||
)
|
)
|
||||||
|
|
||||||
return HTMLBuilder(
|
return HTMLBuilder(
|
||||||
@ -417,6 +417,16 @@ def calendrier_etud():
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
annees: list[int] = sorted(
|
||||||
|
[ins.formsemestre.date_debut.year for ins in etud.formsemestre_inscriptions],
|
||||||
|
reverse=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
annees_str: str = "["
|
||||||
|
for ann in annees:
|
||||||
|
annees_str += f"{ann},"
|
||||||
|
annees_str += "]"
|
||||||
|
|
||||||
return HTMLBuilder(
|
return HTMLBuilder(
|
||||||
header,
|
header,
|
||||||
render_template(
|
render_template(
|
||||||
@ -425,6 +435,7 @@ def calendrier_etud():
|
|||||||
annee=scu.annee_scolaire(),
|
annee=scu.annee_scolaire(),
|
||||||
nonworkdays=_non_work_days(),
|
nonworkdays=_non_work_days(),
|
||||||
minitimeline=_mini_timeline(),
|
minitimeline=_mini_timeline(),
|
||||||
|
annees=annees_str,
|
||||||
),
|
),
|
||||||
).build()
|
).build()
|
||||||
|
|
||||||
@ -840,8 +851,14 @@ def visu_assi_group():
|
|||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"assiduites/pages/visu_assi.j2",
|
"assiduites/pages/visu_assi.j2",
|
||||||
assi_metric=sco_preferences.ASSIDUITES_METRIC_LABEL.get(
|
assi_metric=scu.translate_assiduites_metric(
|
||||||
sco_preferences.get_preference("assi_metrique", dept_id=g.scodoc_dept_id)
|
scu.translate_assiduites_metric(
|
||||||
|
sco_preferences.get_preference(
|
||||||
|
"assi_metrique", dept_id=g.scodoc_dept_id
|
||||||
|
),
|
||||||
|
),
|
||||||
|
inverse=False,
|
||||||
|
short=False,
|
||||||
),
|
),
|
||||||
date_debut=dates["debut"],
|
date_debut=dates["debut"],
|
||||||
date_fin=dates["fin"],
|
date_fin=dates["fin"],
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.6.9"
|
SCOVERSION = "9.6.11"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
15
scodoc.py
15
scodoc.py
@ -661,7 +661,12 @@ def profile(host, port, length, profile_dir):
|
|||||||
@click.option(
|
@click.option(
|
||||||
"-n",
|
"-n",
|
||||||
"--noon",
|
"--noon",
|
||||||
help="Spécifie l'heure de fin du matin (et donc début de l'après-midi) format `hh:mm`",
|
help="Spécifie l'heure de fin du matin format `hh:mm`",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"-a",
|
||||||
|
"--afternoon",
|
||||||
|
help="Spécifie l'heure de début de l'après-midi format `hh:mm` valeur identique à --noon si non spécifié",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"-e",
|
"-e",
|
||||||
@ -670,10 +675,14 @@ def profile(host, port, length, profile_dir):
|
|||||||
)
|
)
|
||||||
@with_appcontext
|
@with_appcontext
|
||||||
def migrate_abs_to_assiduites(
|
def migrate_abs_to_assiduites(
|
||||||
dept: str = None, morning: str = None, noon: str = None, evening: str = None
|
dept: str = None,
|
||||||
|
morning: str = None,
|
||||||
|
noon: str = None,
|
||||||
|
afternoon: str = None,
|
||||||
|
evening: str = None,
|
||||||
): # migrate-abs-to-assiduites
|
): # migrate-abs-to-assiduites
|
||||||
"""Permet de migrer les absences vers le nouveau module d'assiduités"""
|
"""Permet de migrer les absences vers le nouveau module d'assiduités"""
|
||||||
tools.migrate_abs_to_assiduites(dept, morning, noon, evening)
|
tools.migrate_abs_to_assiduites(dept, morning, noon, afternoon, evening)
|
||||||
# import cProfile
|
# import cProfile
|
||||||
# cProfile.runctx(
|
# cProfile.runctx(
|
||||||
# f"tools.migrate_abs_to_assiduites({dept})",
|
# f"tools.migrate_abs_to_assiduites({dept})",
|
||||||
|
@ -4,6 +4,22 @@
|
|||||||
# Prend la version dans le code source local et cherche une release gitea de même tag.
|
# Prend la version dans le code source local et cherche une release gitea de même tag.
|
||||||
# Lance ensuite les tests unitaires locaux.
|
# Lance ensuite les tests unitaires locaux.
|
||||||
|
|
||||||
|
SKIP_TESTS=0
|
||||||
|
while getopts "s" opt; do
|
||||||
|
case "$opt" in
|
||||||
|
s)
|
||||||
|
SKIP_TESTS=1
|
||||||
|
;;
|
||||||
|
\?)
|
||||||
|
echo "Invalid option: -$OPTARG" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
:)
|
||||||
|
echo "Option -$OPTARG requires an argument." >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
# Le répertoire de ce script: .../scodoc/tools
|
# Le répertoire de ce script: .../scodoc/tools
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||||
@ -57,13 +73,17 @@ SCODOC_USER=scodoc
|
|||||||
[ -z "$FACTORY_DIR" ] && die "empty FACTORY_DIR"
|
[ -z "$FACTORY_DIR" ] && die "empty FACTORY_DIR"
|
||||||
[ "$(id -nu)" != "$SCODOC_USER" ] && die "Erreur: le script $0 doit être lancé par l'utilisateur $SCODOC_USER"
|
[ "$(id -nu)" != "$SCODOC_USER" ] && die "Erreur: le script $0 doit être lancé par l'utilisateur $SCODOC_USER"
|
||||||
|
|
||||||
# Tests unitaires lancés dans le répertoire de travail
|
if [ "$SKIP_TESTS" = 1 ]
|
||||||
echo "TESTS UNITAIRES"
|
then
|
||||||
(cd "$UNIT_TESTS_DIR"; pytest tests/unit) || terminate "Erreur dans tests unitaires"
|
echo "SKIPPING UNIT TESTS !"
|
||||||
|
else
|
||||||
# Tests API
|
# Tests unitaires lancés dans le répertoire de travail
|
||||||
(cd "$UNIT_TESTS_DIR"; tools/test_api.sh) || terminate "Erreur dans tests unitaires API"
|
echo "TESTS UNITAIRES"
|
||||||
|
(cd "$UNIT_TESTS_DIR"; pytest tests/unit) || terminate "Erreur dans tests unitaires"
|
||||||
|
|
||||||
|
# Tests API
|
||||||
|
(cd "$UNIT_TESTS_DIR"; tools/test_api.sh) || terminate "Erreur dans tests unitaires API"
|
||||||
|
fi
|
||||||
|
|
||||||
# Création répertoire du paquet, et de opt
|
# Création répertoire du paquet, et de opt
|
||||||
slash="$FACTORY_DIR"/"$DEST_DIR"
|
slash="$FACTORY_DIR"/"$DEST_DIR"
|
||||||
|
@ -45,7 +45,7 @@ then
|
|||||||
PSQL=/usr/lib/postgresql/15/bin/psql
|
PSQL=/usr/lib/postgresql/15/bin/psql
|
||||||
#export POSTGRES_SERVICE="postgresql@11-main.service"
|
#export POSTGRES_SERVICE="postgresql@11-main.service"
|
||||||
else
|
else
|
||||||
die "unsupported Debian version"
|
die "unsupported Debian version (${debian_version}, expected 12)"
|
||||||
fi
|
fi
|
||||||
export PSQL
|
export PSQL
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ class _glob:
|
|||||||
|
|
||||||
MORNING: time = None
|
MORNING: time = None
|
||||||
NOON: time = None
|
NOON: time = None
|
||||||
|
AFTERNOON: time = None
|
||||||
EVENING: time = None
|
EVENING: time = None
|
||||||
|
|
||||||
|
|
||||||
@ -93,7 +94,7 @@ class _Merger:
|
|||||||
time_ = _glob.NOON if end else _glob.MORNING
|
time_ = _glob.NOON if end else _glob.MORNING
|
||||||
date_ = datetime.combine(couple[0], time_)
|
date_ = datetime.combine(couple[0], time_)
|
||||||
else:
|
else:
|
||||||
time_ = _glob.EVENING if end else _glob.NOON
|
time_ = _glob.EVENING if end else _glob.AFTERNOON
|
||||||
date_ = datetime.combine(couple[0], time_)
|
date_ = datetime.combine(couple[0], time_)
|
||||||
d = localize_datetime(date_)
|
d = localize_datetime(date_)
|
||||||
return d
|
return d
|
||||||
@ -229,6 +230,7 @@ def migrate_abs_to_assiduites(
|
|||||||
dept: str = None,
|
dept: str = None,
|
||||||
morning: str = None,
|
morning: str = None,
|
||||||
noon: str = None,
|
noon: str = None,
|
||||||
|
afternoon: str = None,
|
||||||
evening: str = None,
|
evening: str = None,
|
||||||
debug: bool = False,
|
debug: bool = False,
|
||||||
):
|
):
|
||||||
@ -266,6 +268,12 @@ def migrate_abs_to_assiduites(
|
|||||||
noon: list[str] = str(noon).split(":")
|
noon: list[str] = str(noon).split(":")
|
||||||
_glob.NOON = time(int(noon[0]), int(noon[1]))
|
_glob.NOON = time(int(noon[0]), int(noon[1]))
|
||||||
|
|
||||||
|
if afternoon is None:
|
||||||
|
afternoon = ScoDocSiteConfig.get("assi_lunch_time", time(13, 0))
|
||||||
|
|
||||||
|
afternoon: list[str] = str(afternoon).split(":")
|
||||||
|
_glob.AFTERNOON = time(int(afternoon[0]), int(afternoon[1]))
|
||||||
|
|
||||||
if evening is None:
|
if evening is None:
|
||||||
evening = ScoDocSiteConfig.get("assi_afternoon_time", time(18, 0))
|
evening = ScoDocSiteConfig.get("assi_afternoon_time", time(18, 0))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user