doc et tests unitaires des absences

This commit is contained in:
Emmanuel Viennet 2021-08-01 00:05:53 +03:00
parent 6a42846d2e
commit 37e7667eeb
8 changed files with 547 additions and 248 deletions

View File

@ -306,11 +306,14 @@ def list_abs_in_range(etudid, debut, fin, matin=None, moduleimpl_id=None, cursor
"""Liste des absences entre deux dates.
Args:
etudid
debut string iso date ("2020-03-12")
end string iso date ("2020-03-12")
matin None, True, False
moduleimpl_id
etudid:
debut: string iso date ("2020-03-12")
end: string iso date ("2020-03-12")
matin: None, True, False
moduleimpl_id: restreint le comptage aux absences dans ce module
Returns:
List of absences
"""
if matin != None:
matin = _toboolean(matin)
@ -347,9 +350,15 @@ WHERE A.ETUDID = %(etudid)s
return res
def count_abs(etudid, debut, fin, matin=None, moduleimpl_id=None):
"""CountAbs
matin= 1 ou 0.
def count_abs(etudid, debut, fin, matin=None, moduleimpl_id=None) -> int:
"""compte le nombre d'absences
Args:
etudid: l'étudiant considéré
debut: date, chaîne iso, eg "2021-06-15"
fin: date de fin, incluse
matin: True (compte les matinées), False (les après-midi), None (les deux)
moduleimpl_id: restreint le comptage aux absences dans ce module.
Returns:
An integer.
@ -359,8 +368,19 @@ def count_abs(etudid, debut, fin, matin=None, moduleimpl_id=None):
)
def count_abs_just(etudid, debut, fin, matin=None, moduleimpl_id=None):
"Count just. abs"
def count_abs_just(etudid, debut, fin, matin=None, moduleimpl_id=None) -> int:
"""compte le nombre d'absences justifiées
Args:
etudid: l'étudiant considéré
debut: date, chaîne iso, eg "2021-06-15"
fin: date de fin, incluse
matin: True (compte les matinées), False (les après-midi), None (les deux)
moduleimpl_id: restreint le comptage aux absences dans ce module.
Returns:
An integer.
"""
if matin != None:
matin = _toboolean(matin)
ismatin = " AND A.MATIN = %(matin)s "
@ -569,9 +589,20 @@ ORDER BY A.JOUR
def list_abs_justifs(etudid, datedebut, datefin=None, only_no_abs=False):
"""Liste des justificatifs (sans absence relevée) à partir d'une date,
"""Liste des justificatifs (avec ou sans absence relevée) à partir d'une date,
ou, si datefin spécifié, entre deux dates.
Si only_no_abs: seulement les justificatifs correspondant aux jours sans absences relevées.
Args:
etudid:
datedebut: date de début, iso, eg "2002-03-15"
datefin: date de fin, incluse, eg "2002-03-15"
only_no_abs: si vrai, seulement les justificatifs correspondant
aux jours sans absences relevées.
Returns:
Liste de dict absences
{'etudid': 'EID214', 'jour': datetime.date(2021, 1, 15),
'matin': True, 'description': ''
}
"""
cnx = ndb.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
@ -664,9 +695,16 @@ def _add_abslist(context, abslist, REQUEST, moduleimpl_id=None):
add_absence(context, etudid, jour, matin, 0, REQUEST, "", moduleimpl_id)
def annule_absence(context, etudid, jour, matin, moduleimpl_id=None, REQUEST=None):
"""Annule une absence ds base
Si moduleimpl_id, n'annule que pour ce module
def annule_absence(context, etudid, jour, matin, moduleimpl_id=None):
"""Annule une absence dans la base. N'efface pas l'éventuel justificatif.
Args:
etudid:
jour: date, chaîne iso, eg "1999-12-31"
matin:
moduleimpl_id: si spécifié, n'annule que pour ce module.
Returns:
None
"""
# unpublished
matin = _toboolean(matin)

View File

@ -433,11 +433,11 @@ def doAnnuleAbsence(
demijournee = int(demijournee)
for jour in dates:
if demijournee == 2:
sco_abs.annule_absence(context, etudid, jour, False, REQUEST=REQUEST)
sco_abs.annule_absence(context, etudid, jour, True, REQUEST=REQUEST)
sco_abs.annule_absence(context, etudid, jour, False)
sco_abs.annule_absence(context, etudid, jour, True)
nbadded += 2
else:
sco_abs.annule_absence(context, etudid, jour, demijournee, REQUEST=REQUEST)
sco_abs.annule_absence(context, etudid, jour, demijournee)
nbadded += 1
#
H = [
@ -608,9 +608,16 @@ autre absence pour <b>%(nomprenom)s</b></a></li>
return "\n".join(H)
def AnnuleAbsencesDatesNoJust(context, etudid, dates, moduleimpl_id=None, REQUEST=None):
"""Supprime les absences aux dates indiquées
mais ne supprime pas les justificatifs.
def AnnuleAbsencesDatesNoJust(context, etudid, dates, moduleimpl_id=None):
"""Supprime les absences non justifiées aux dates indiquées
Ne supprime pas les justificatifs éventuels.
Args:
etudid: l'étudiant
dates: liste de dates iso, eg [ "2000-01-15", "2000-01-16" ]
moduleimpl_id: si spécifié, n'affecte que les absences de ce module
Returns:
None
"""
# log('AnnuleAbsencesDatesNoJust: moduleimpl_id=%s' % moduleimpl_id)
if not dates:
@ -626,7 +633,7 @@ def AnnuleAbsencesDatesNoJust(context, etudid, dates, moduleimpl_id=None, REQUES
matin = 0
else:
raise ValueError("invalid ampm !")
sco_abs.annule_absence(context, etudid, jour, matin, moduleimpl_id, REQUEST)
sco_abs.annule_absence(context, etudid, jour, matin, moduleimpl_id)
return
cnx = ndb.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)

View File

@ -295,7 +295,7 @@ def doSignaleAbsenceGrSemestre(
if dates:
for etudid in etudids:
sco_abs_views.AnnuleAbsencesDatesNoJust(
context, etudid, dates, moduleimpl_id, REQUEST
context, etudid, dates, moduleimpl_id
)
return "Absences effacées"

View File

@ -48,10 +48,17 @@ G.inscrit_etudiant(sem, etud)
etudid = etud["etudid"]
# --- Création d'une absence
sco_abs_views.doSignaleAbsence(context.Absences, datedebut="22/01/2021", datefin="22/01/2021", demijournee=2, etudid=etudid, REQUEST=REQUEST)
sco_abs_views.doSignaleAbsence(
context.Absences,
datedebut="22/01/2021",
datefin="22/01/2021",
demijournee=2,
etudid=etudid,
REQUEST=REQUEST,
)
# --- Annulation d'absence
context.Absences.AnnuleAbsencesDatesNoJust(etudid, dates="22/01/2021", REQUEST=REQUEST)
context.Absences.AnnuleAbsencesDatesNoJust(etudid, dates="22/01/2021")
""" Erreur : File "/opt/scodoc/Products/ScoDoc/ZAbsences.py", line 323, in AnnuleAbsencesDatesNoJust
vars(),

View File

@ -236,7 +236,7 @@ assert len(li_range) == 5
# --- Annulation d'absence
# context.Absences.AnnuleAbsencesDatesNoJust(etudid, dates="22/01/2021", REQUEST=REQUEST)
# context.Absences.AnnuleAbsencesDatesNoJust(etudid, dates="22/01/2021")
# --- Fonction renvoyant du code HTML

View File

@ -1,17 +1,26 @@
import random
# -*- mode: python -*-
# -*- coding: utf-8 -*-
# La variable context est définie par le script de lancement
# l'affecte ainsi pour évietr les warnins pylint:
context = context # pylint: disable=undefined-variable
REQUEST = REQUEST # pylint: disable=undefined-variable
import scotests.sco_fake_gen as sco_fake_gen # pylint: disable=import-error
import sco_abs
import sco_abs_views
import sco_abs_notification
import ZAbsences
"""
Comptage des absences
"""
# test écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en juillet 2021
G = sco_fake_gen.ScoFake(context.Notes)
G.verbose = False
import json
from tests.unit import sco_fake_gen
from app.scodoc import sco_abs
from app.scodoc import sco_abs_views
from app.scodoc import sco_groups
from app.views import absences
context = None # #context
def test_abs_counts(test_client):
"""Comptage des absences"""
G = sco_fake_gen.ScoFake(verbose=False)
# --- Création d'étudiants
etud = G.create_etud(code_nip=None)
@ -50,21 +59,21 @@ G.inscrit_etudiant(sem, etud)
etudid = etud["etudid"]
for debut, fin, demijournee in [
("01/01/2020", "31/01/2020", 2), # hors semestre
("15/01/2021", "15/01/2021", 1),
("18/01/2021", "18/01/2021", 0),
("19/01/2021", "19/01/2021", 2),
("22/01/2021", "22/01/2021", 1),
("30/06/2021", "30/06/2021", 2), # dernier jour
]:
sco_abs_views.doSignaleAbsence(
context.Absences,
context,
datedebut=debut,
datefin=fin,
demijournee=demijournee,
etudid=etudid,
REQUEST=REQUEST,
)
# --- Justification de certaines absences
for debut, fin, demijournee in [
@ -73,54 +82,49 @@ for debut, fin, demijournee in [
("19/01/2021", "19/01/2021", 2),
]:
sco_abs_views.doJustifAbsence(
context.Absences,
context,
datedebut=debut,
datefin=fin,
demijournee=demijournee,
etudid=etudid,
REQUEST=REQUEST,
)
# --- Utilisation de get_abs_count() de sco_abs
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
# --- Utilisation de sco_abs.count_abs()
# --- Utilisation de CountAbs() de ZAbsences
nb_abs2 = context.Absences.CountAbs(etudid=etudid, debut="01/01/2021", fin="06/30/2021")
nb_absj2 = context.Absences.CountAbsJust(
etudid=etudid, debut="01/01/2021", fin="06/30/2021"
nb_abs2 = sco_abs.count_abs(etudid=etudid, debut="2021-01-01", fin="2021-06-30")
nb_absj2 = sco_abs.count_abs_just(
etudid=etudid, debut="2021-01-01", fin="2021-06-30"
)
assert nbabs == nb_abs2 == 5
assert nbabs == nb_abs2 == 7
assert nbabsjust == nb_absj2 == 4
# --- Suppression d'absence
# --- Nombre de justificatifs:
justifs = sco_abs.list_abs_justifs(etudid, "2021-01-01", datefin="2021-06-30")
assert len(justifs) == 4
# --- Suppression d'absence
_ = sco_abs_views.doAnnuleAbsence(
context.Absences, "19/01/2021", "19/01/2021", 2, etudid=etudid, REQUEST=REQUEST
context, "19/01/2021", "19/01/2021", 2, etudid=etudid
)
# --- Vérification
new_nbabs, _ = sco_abs.get_abs_count(etudid, sem)
new_nbabs2 = context.Absences.CountAbs(
etudid=etudid, debut="01/01/2021", fin="06/30/2021"
)
print(new_nbabs)
print(new_nbabs2)
justifs_2 = sco_abs.list_abs_justifs(etudid, "2021-01-01", datefin="2021-06-30")
assert len(justifs_2) == len(justifs)
new_nbabs, _ = sco_abs.get_abs_count(etudid, sem) # version cachée
new_nbabs2 = sco_abs.count_abs(etudid=etudid, debut="2021-01-01", fin="2021-06-30")
assert new_nbabs == new_nbabs2
assert new_nbabs == (nbabs - 2) # on a supprimé deux absences
"""
Commentaire :
CountAbs de ZAbsence ----> OK
CountAbs de sco_abs_view ----> bug
Peut être du au fait que la fonction getAbsSemEtud ne se met pas à jour par rapport aux absences supprimés.
"""
# --- annulation absence sans supprimer le justificatif
sco_abs_views.AnnuleAbsencesDatesNoJust(context, etudid, ["2021-01-15"])
nbabs_3, nbjust_3 = sco_abs.get_abs_count(etudid, sem)
assert nbabs_3 == new_nbabs
justifs_3 = sco_abs.list_abs_justifs(etudid, "2021-01-01", datefin="2021-06-30")
assert len(justifs_3) == len(justifs_2)
# XXX à continuer

View File

@ -1,19 +1,28 @@
""" Parametre demijournee ne fonctionne pas lorsque demijournee = 2
# -*- mode: python -*-
# -*- coding: utf-8 -*-
"""
Créer et justifier des absences en utilisant le parametre demijournee
"""
import random
# test écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en juillet 2021
# La variable context est définie par le script de lancement
# l'affecte ainsi pour évietr les warnins pylint:
context = context # pylint: disable=undefined-variable
REQUEST = REQUEST # pylint: disable=undefined-variable
import scotests.sco_fake_gen as sco_fake_gen # pylint: disable=import-error
import sco_abs
import sco_abs_views
import sco_abs_notification
import json
G = sco_fake_gen.ScoFake(context.Notes)
G.verbose = False
from tests.unit import sco_fake_gen
from app.scodoc import sco_abs
from app.scodoc import sco_abs_views
from app.scodoc import sco_groups
from app.views import absences
context = None # #context
def test_abs_demijournee(test_client):
"""Opération élémentaires sur les absences, tests demi-journées
Travaille dans base TEST00 (defaut)
"""
G = sco_fake_gen.ScoFake(verbose=False)
# --- Création d'étudiants
etud = G.create_etud(code_nip=None)
@ -48,56 +57,49 @@ mi = G.create_moduleimpl(
# --- Inscription des étudiants
G.inscrit_etudiant(sem, etud)
# --- Saisie absences
etudid = etud["etudid"]
_ = sco_abs_views.doSignaleAbsence(
context.Absences,
context,
"15/01/2021",
"15/01/2021",
demijournee=2,
etudid=etudid,
REQUEST=REQUEST,
)
_ = sco_abs_views.doSignaleAbsence(
context.Absences,
context,
"18/01/2021",
"18/01/2021",
demijournee=1,
etudid=etudid,
REQUEST=REQUEST,
)
_ = sco_abs_views.doSignaleAbsence(
context.Absences,
context,
"19/01/2021",
"19/01/2021",
demijournee=0,
etudid=etudid,
REQUEST=REQUEST,
)
# --- Justification de certaines absences
_ = sco_abs_views.doJustifAbsence(
context.Absences,
context,
"18/01/2021",
"18/01/2021",
demijournee=1,
etudid=etudid,
REQUEST=REQUEST,
)
_ = sco_abs_views.doJustifAbsence(
context.Absences,
context,
"19/01/2021",
"19/01/2021",
demijournee=2,
etudid=etudid,
REQUEST=REQUEST,
)
# NE JUSTIFIE QUE LE MATIN MALGRES LE PARAMETRE demijournee = 2
@ -110,10 +112,249 @@ assert (
) # l'étudiant a été absent le 15 journée compléte (2 abs : 1 matin, 1 apres midi) et le 18 (1 matin), et le 19 (1 apres midi).
assert nbabs_just == 2 # Justifie abs du matin + abs après midi
"""
Commentaire :
Pb : le 2 ne peut pas être pris en tant que int car string dans la fonction
-----> Pb reglé
def test_abs_basic(test_client):
"""creation de 10 étudiants, formation, semestre, ue, module, absences le matin, l'apres midi, la journée compléte
et justification d'absences, supression d'absences, création d'une liste etat absences, creation d'un groupe afin
de tester la fonction EtatAbsencesGroupes
Fonctions de l'API utilisé :
- doSignaleAbsence
- doAnnuleAbsence
- doJustifAbsence
- get_partition_groups
- get_partitions_list
- sco_abs.get_abs_count(etudid, sem)
- ListeAbsEtud
- partition_create
- createGroup
- set_group
- EtatAbsenceGr
- AddBilletAbsence
- listeBilletsEtud
"""
G = sco_fake_gen.ScoFake(verbose=False)
# --- Création d'étudiants
etuds = [G.create_etud(code_nip=None) for _ in range(10)]
# --- Création d'une formation
f = G.create_formation(acronyme="")
ue = G.create_ue(formation_id=f["formation_id"], acronyme="TST1", titre="ue test")
mat = G.create_matiere(ue_id=ue["ue_id"], titre="matière test")
mod = G.create_module(
matiere_id=mat["matiere_id"],
code="TSM1",
coefficient=1.0,
titre="module test",
ue_id=ue["ue_id"], # faiblesse de l'API
formation_id=f["formation_id"], # faiblesse de l'API
)
# --- Mise place d'un semestre
sem = G.create_formsemestre(
formation_id=f["formation_id"],
semestre_id=1,
date_debut="01/01/2021",
date_fin="30/06/2021",
)
mi = G.create_moduleimpl(
module_id=mod["module_id"],
formsemestre_id=sem["formsemestre_id"],
responsable_id="bach",
)
# --- Inscription des étudiants
for etud in etuds:
G.inscrit_etudiant(sem, etud)
# --- Création d'une évaluation
e = G.create_evaluation(
moduleimpl_id=mi["moduleimpl_id"],
jour="22/01/2021",
description="evaluation test",
coefficient=1.0,
)
# --- Saisie absences
etudid = etuds[0]["etudid"]
_ = sco_abs_views.doSignaleAbsence(
context,
"15/01/2021",
"15/01/2021",
demijournee=1,
etudid=etudid,
)
_ = sco_abs_views.doSignaleAbsence(
context,
"18/01/2021",
"18/01/2021",
demijournee=0,
etudid=etudid,
)
_ = sco_abs_views.doSignaleAbsence(
context,
"19/01/2021",
"19/01/2021",
demijournee=2,
etudid=etudid,
)
_ = sco_abs_views.doSignaleAbsence(
context,
"22/01/2021",
"22/01/2021",
demijournee=1,
etudid=etudid,
)
# --- Justification de certaines absences
_ = sco_abs_views.doJustifAbsence(
context,
"15/01/2021",
"15/01/2021",
demijournee=1,
etudid=etudid,
)
_ = sco_abs_views.doJustifAbsence(
context,
"18/01/2021",
"18/01/2021",
demijournee=0,
etudid=etudid,
)
_ = sco_abs_views.doJustifAbsence(
context,
"19/01/2021",
"19/01/2021",
demijournee=2,
etudid=etudid,
)
# --- Test
b = sco_abs.is_work_saturday(context)
assert b == 0 # samedi ne sont pas compris
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
assert (
nbabs == 5
) # l'étudiant a été absent le 15 (apres midi) , (16 et 17 we), 18 (matin) et 19 janvier (matin et apres midi), et 22 (matin)
assert nbabsjust == 4 # l'étudiant justifie ses abs du 15, 18 et 19
# + vérification à l'aide de ScoDoc WEB : ok!
# --- Supression d'une absence et d'une justification
_ = sco_abs_views.doAnnuleAbsence(
context, "19/01/2021", "19/01/2021", 2, etudid=etudid
)
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
print(nbabs) # lors du print cela affiche 5 or cela devrait afficher 3
# assert nbabs == 3
# + vérification à l'aide de ScoDoc WEB : il y a bien plus que 3 abs, 2 justifiés et 1 non justifié.
# --- supression d'une justification pas encore disponible à l'aide de python.
# --- Création d'une liste d'abs
liste_abs = sco_abs_views.ListeAbsEtud(
context, etudid, format="json", absjust_only=1
)
liste_abs2 = sco_abs_views.ListeAbsEtud(context, etudid, format="json")
load_liste_abs = json.loads(liste_abs)
load_liste_abs2 = json.loads(liste_abs2)
assert len(load_liste_abs2) == 1
assert len(load_liste_abs) == 2
assert load_liste_abs2[0]["ampm"] == "1"
assert load_liste_abs2[0]["datedmy"] == "22/01/2021"
assert load_liste_abs2[0]["exams"] == mod["code"]
# absjust_only -> seulement les abs justifiés
# --- Création d'un groupe
_ = sco_groups.partition_create(
context,
formsemestre_id=sem["formsemestre_id"],
partition_name="Eleve",
)
li1 = sco_groups.get_partitions_list(context, sem["formsemestre_id"])
_ = sco_groups.createGroup(context, li1[0]["partition_id"], "Groupe 1")
# --- Affectation des élèves dans des groupes
li_grp1 = sco_groups.get_partition_groups(context, li1[0])
for etud in etuds:
sco_groups.set_group(context, etud["etudid"], li_grp1[0]["group_id"])
# --- Test de EtatAbsencesGroupes
grp1_abs = absences.EtatAbsencesGr(
context,
group_ids=[li_grp1[0]["group_id"]],
debut="01/01/2021",
fin="30/06/2021",
format="json",
)
# grp1_abs est une Response car on a appelé une vue (1er appel)
load_grp1_abs = json.loads(grp1_abs.get_data().decode("utf-8"))
assert len(load_grp1_abs) == 10
tab_id = [] # tab des id present dans load_grp1_abs
for un_etud in load_grp1_abs:
tab_id.append(un_etud["etudid"])
for (
etud
) in (
etuds
): # verification si tous les etudiants sont present dans la liste du groupe d'absence
assert etud["etudid"] in tab_id
for un_etud in load_grp1_abs:
if un_etud["etudid"] == etudid:
assert un_etud["nbabs"] == "3"
assert un_etud["nbjustifs_noabs"] == "2"
assert un_etud["nbabsjust"] == "2"
assert un_etud["nbabsnonjust"] == "1"
assert un_etud["nomprenom"] == etuds[0]["nomprenom"]
# --- Création de billets
b1 = absences.AddBilletAbsence(
context,
begin="2021-01-22 00:00",
end="2021-01-22 23:59",
etudid=etudid,
description="abs du 22",
justified=False,
code_nip=etuds[0]["code_nip"],
code_ine=etuds[0]["code_ine"],
)
b2 = absences.AddBilletAbsence(
context,
begin="2021-01-15 00:00",
end="2021-01-15 23:59",
etudid=etudid,
description="abs du 15",
code_nip=etuds[0]["code_nip"],
code_ine=etuds[0]["code_ine"],
)
li_bi = absences.listeBilletsEtud(context, etudid=etudid, format="json")
assert isinstance(li_bi, str)
load_li_bi = json.loads(li_bi)
assert len(load_li_bi) == 2
assert load_li_bi[1]["description"] == "abs du 22"

View File

@ -22,7 +22,9 @@ context = None # #context
def test_notes_table(test_client):
"""Test construction et cache de NotesTable"""
"""Test construction et cache de NotesTable.
Attention: utilise une base (departement) existante.
"""
ndb.set_sco_dept(DEPT)
assert g.scodoc_dept == DEPT
sems = sco_formsemestre.do_formsemestre_list(context)