API: export JSOn des bulletins des semestres d'une annee scolaire.

This commit is contained in:
viennet 2020-12-12 17:22:54 +01:00
parent 912c1dbd0b
commit 612b62227c
4 changed files with 73 additions and 27 deletions

View File

@ -249,6 +249,9 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
security.declareProtected(ScoView, "formsemestre_recapcomplet") security.declareProtected(ScoView, "formsemestre_recapcomplet")
formsemestre_recapcomplet = sco_recapcomplet.formsemestre_recapcomplet formsemestre_recapcomplet = sco_recapcomplet.formsemestre_recapcomplet
security.declareProtected(ScoObservateur, "formsemestres_bulletins")
formsemestres_bulletins = sco_recapcomplet.formsemestres_bulletins
security.declareProtected(ScoView, "moduleimpl_status") security.declareProtected(ScoView, "moduleimpl_status")
moduleimpl_status = sco_moduleimpl_status.moduleimpl_status moduleimpl_status = sco_moduleimpl_status.moduleimpl_status

View File

@ -124,8 +124,7 @@ def do_formsemestre_list(context, *a, **kw):
def formsemestre_enrich(context, sem): def formsemestre_enrich(context, sem):
"""Ajoute champs souvent utiles: titre + annee et dateord (pour tris) """Ajoute champs souvent utiles: titre + annee et dateord (pour tris)"""
"""
# imports ici pour eviter refs circulaires # imports ici pour eviter refs circulaires
import sco_formsemestre_edit import sco_formsemestre_edit
import scolars import scolars
@ -294,8 +293,7 @@ class ApoEtapeVDI:
_ETAPE_VDI_SEP = "!" _ETAPE_VDI_SEP = "!"
def __init__(self, etape_vdi=None, etape="", vdi=""): def __init__(self, etape_vdi=None, etape="", vdi=""):
"""Build from string representation, e.g. 'V1RT!111' """Build from string representation, e.g. 'V1RT!111'"""
"""
if etape_vdi: if etape_vdi:
self.etape_vdi = etape_vdi self.etape_vdi = etape_vdi
self.etape, self.vdi = self.split_etape_vdi(etape_vdi) self.etape, self.vdi = self.split_etape_vdi(etape_vdi)
@ -371,11 +369,11 @@ def sem_set_responsable_name(context, sem):
def sem_in_semestre_scolaire(context, sem, year=False, saison=0, REQUEST=None): def sem_in_semestre_scolaire(context, sem, year=False, saison=0, REQUEST=None):
"""n'utilise que la date de debut, pivot au 1er aout """n'utilise que la date de debut, pivot au 1er aout
si annee non specifiée, année scolaire courante si annee non specifiée, année scolaire courante
Patch Jmp: ajout du parametre optionnel saison Patch Jmp: ajout du parametre optionnel saison
1 = sept, 0 = janvier, None = année complète 1 = sept, 0 = janvier, None = année complète
si saison non spécifiée: année complète si saison non spécifiée: année complète
pivot de saison au 1er décembre pivot de saison au 1er décembre
XXX TODO: la période (ici appelée "saison" devrait être éditable XXX TODO: la période (ici appelée "saison" devrait être éditable
manuellement dans le formsemestre_edit afin de couvrir els cas particulier manuellement dans le formsemestre_edit afin de couvrir els cas particulier
comme un semestre S2 qui commecerait en décembre... voire novembre. comme un semestre S2 qui commecerait en décembre... voire novembre.
) )
@ -417,17 +415,20 @@ def sem_une_annee(context, sem):
pivot au 1er août. pivot au 1er août.
""" """
if sem["date_debut_iso"] > sem["date_fin_iso"]: if sem["date_debut_iso"] > sem["date_fin_iso"]:
log('Warning: semestre %(formsemestre_id)s begins after ending !' % sem) log("Warning: semestre %(formsemestre_id)s begins after ending !" % sem)
return False return False
debut = int(sem["annee_debut"]) debut = int(sem["annee_debut"])
if sem["mois_debut_ord"] < 8: # considere que debut sur l'anne scolaire precedente if sem["mois_debut_ord"] < 8: # considere que debut sur l'anne scolaire precedente
debut -= 1 debut -= 1
fin = int(sem["annee_fin"]) fin = int(sem["annee_fin"])
if sem["mois_fin_ord"] < 9: # 9 (sept) pour autoriser un début en sept et une fin en aout if (
sem["mois_fin_ord"] < 9
): # 9 (sept) pour autoriser un début en sept et une fin en aout
fin -= 1 fin -= 1
return debut == fin return debut == fin
def scodoc_get_all_unlocked_sems(context): def scodoc_get_all_unlocked_sems(context):
"""Liste de tous les semestres non verrouillés de tous les départements""" """Liste de tous les semestres non verrouillés de tous les départements"""
depts = context.list_depts() depts = context.list_depts()
@ -450,8 +451,7 @@ def table_formsemestres(
html_next_section="", html_next_section="",
REQUEST=None, REQUEST=None,
): ):
"""Une table presentant des semestres """Une table presentant des semestres"""
"""
for sem in sems: for sem in sems:
sem_set_responsable_name(context, sem) sem_set_responsable_name(context, sem)
sem["_titre_num_target"] = ( sem["_titre_num_target"] = (
@ -498,17 +498,16 @@ def table_formsemestres(
def list_formsemestre_by_etape( def list_formsemestre_by_etape(
context, etape_apo=None, annee_scolaire=False, REQUEST=None context, etape_apo=False, annee_scolaire=False, REQUEST=None
): ):
"""Liste des semestres de cette etape, pour l'annee scolaire indiquée (sinon, pour toutes) """Liste des semestres de cette etape, pour l'annee scolaire indiquée (sinon, pour toutes)"""
"""
ds = {} # formsemestre_id : sem ds = {} # formsemestre_id : sem
if etape_apo: if etape_apo:
sems = do_formsemestre_list(context, args={"etape_apo": etape_apo}) sems = do_formsemestre_list(context, args={"etape_apo": etape_apo})
for sem in sems: for sem in sems:
if annee_scolaire: # restriction annee scolaire if annee_scolaire: # restriction annee scolaire
if sem_in_annee_scolaire( if sem_in_annee_scolaire(
context, sem, year=annee_scolaire, REQUEST=REQUEST context, sem, year=int(annee_scolaire), REQUEST=REQUEST
): ):
ds[sem["formsemestre_id"]] = sem ds[sem["formsemestre_id"]] = sem
sems = ds.values() sems = ds.values()
@ -519,7 +518,7 @@ def list_formsemestre_by_etape(
sem sem
for sem in sems for sem in sems
if sem_in_annee_scolaire( if sem_in_annee_scolaire(
context, sem, year=annee_scolaire, REQUEST=REQUEST context, sem, year=int(annee_scolaire), REQUEST=REQUEST
) )
] ]
@ -528,8 +527,7 @@ def list_formsemestre_by_etape(
def view_formsemestre_by_etape(context, etape_apo=None, format="html", REQUEST=None): def view_formsemestre_by_etape(context, etape_apo=None, format="html", REQUEST=None):
"""Affiche table des semestres correspondants à l'étape """Affiche table des semestres correspondants à l'étape"""
"""
if etape_apo: if etape_apo:
html_title = ( html_title = (
"""<h2>Semestres courants de l'étape <tt>%s</tt></h2>""" % etape_apo """<h2>Semestres courants de l'étape <tt>%s</tt></h2>""" % etape_apo

View File

@ -35,7 +35,7 @@ ScoEditFormationTags = (
ScoView = "Sco View" ScoView = "Sco View"
ScoEnsView = "Sco View Ens" # parties visibles par enseignants slt ScoEnsView = "Sco View Ens" # parties visibles par enseignants slt
ScoObservateur = "Sco Observateur" # accès lecture restreint aux bulletins
ScoUsersAdmin = "Sco Users Manage" ScoUsersAdmin = "Sco Users Manage"
ScoUsersView = "Sco Users View" ScoUsersView = "Sco Users View"
@ -51,6 +51,7 @@ ScoSuperAdmin = "Sco Super Admin"
# Default permissions for default roles # Default permissions for default roles
# (set once on instance creation): # (set once on instance creation):
Sco_Default_Permissions = { Sco_Default_Permissions = {
ScoObservateur: ("Ens", "Secr", "Admin", "RespPe"),
ScoView: ("Ens", "Secr", "Admin", "RespPe"), ScoView: ("Ens", "Secr", "Admin", "RespPe"),
ScoEnsView: ("Ens", "Admin", "RespPe"), ScoEnsView: ("Ens", "Admin", "RespPe"),
ScoUsersView: ("Ens", "Secr", "Admin", "RespPe"), ScoUsersView: ("Ens", "Secr", "Admin", "RespPe"),

View File

@ -51,6 +51,7 @@ def formsemestre_recapcomplet(
xml_with_decisions=False, # XML avec decisions xml_with_decisions=False, # XML avec decisions
rank_partition_id=None, # si None, calcul rang global rank_partition_id=None, # si None, calcul rang global
pref_override=True, # si vrai, les prefs ont la priorite sur le param hidebac pref_override=True, # si vrai, les prefs ont la priorite sur le param hidebac
force_publishing=True, # publie les XML/JSON meme si bulletins non publiés
REQUEST=None, REQUEST=None,
): ):
"""Page récapitulant les notes d'un semestre. """Page récapitulant les notes d'un semestre.
@ -72,6 +73,7 @@ def formsemestre_recapcomplet(
else: else:
hidebac = int(hidebac) hidebac = int(hidebac)
xml_with_decisions = int(xml_with_decisions) xml_with_decisions = int(xml_with_decisions)
force_publishing = int(force_publishing)
isFile = tabformat in ("csv", "xls", "xml", "xlsall", "json") isFile = tabformat in ("csv", "xls", "xml", "xlsall", "json")
H = [] H = []
if not isFile: if not isFile:
@ -144,6 +146,7 @@ def formsemestre_recapcomplet(
sortcol=sortcol, sortcol=sortcol,
xml_with_decisions=xml_with_decisions, xml_with_decisions=xml_with_decisions,
rank_partition_id=rank_partition_id, rank_partition_id=rank_partition_id,
force_publishing=force_publishing,
) )
) )
@ -191,6 +194,7 @@ def do_formsemestre_recapcomplet(
xml_with_decisions=False, xml_with_decisions=False,
disable_etudlink=False, disable_etudlink=False,
rank_partition_id=None, # si None, calcul rang global rank_partition_id=None, # si None, calcul rang global
force_publishing=True,
): ):
"""Calcule et renvoie le tableau récapitulatif.""" """Calcule et renvoie le tableau récapitulatif."""
data, filename, format = make_formsemestre_recapcomplet(**vars()) data, filename, format = make_formsemestre_recapcomplet(**vars())
@ -219,6 +223,7 @@ def make_formsemestre_recapcomplet(
xml_with_decisions=False, xml_with_decisions=False,
disable_etudlink=False, disable_etudlink=False,
rank_partition_id=None, # si None, calcul rang global rank_partition_id=None, # si None, calcul rang global
force_publishing=True, # donne bulletins JSON/XML meme si non publiés
): ):
"""Grand tableau récapitulatif avec toutes les notes de modules """Grand tableau récapitulatif avec toutes les notes de modules
pour tous les étudiants, les moyennes par UE et générale, pour tous les étudiants, les moyennes par UE et générale,
@ -226,11 +231,19 @@ def make_formsemestre_recapcomplet(
""" """
if format == "xml": if format == "xml":
return _formsemestre_recapcomplet_xml( return _formsemestre_recapcomplet_xml(
context, formsemestre_id, xml_nodate, xml_with_decisions=xml_with_decisions context,
formsemestre_id,
xml_nodate,
xml_with_decisions=xml_with_decisions,
force_publishing=force_publishing,
) )
elif format == "json": elif format == "json":
return _formsemestre_recapcomplet_json( return _formsemestre_recapcomplet_json(
context, formsemestre_id, xml_nodate, xml_with_decisions=xml_with_decisions context,
formsemestre_id,
xml_nodate=xml_nodate,
xml_with_decisions=xml_with_decisions,
force_publishing=force_publishing,
) )
if format[:3] == "xls": if format[:3] == "xls":
keep_numeric = True # pas de conversion des notes en strings keep_numeric = True # pas de conversion des notes en strings
@ -791,7 +804,11 @@ def _list_notes_evals_stats(context, evals, key):
def _formsemestre_recapcomplet_xml( def _formsemestre_recapcomplet_xml(
context, formsemestre_id, xml_nodate, xml_with_decisions=False context,
formsemestre_id,
xml_nodate,
xml_with_decisions=False,
force_publishing=True,
): ):
"XML export: liste tous les bulletins XML." "XML export: liste tous les bulletins XML."
@ -825,7 +842,7 @@ def _formsemestre_recapcomplet_xml(
formsemestre_id, formsemestre_id,
etudid, etudid,
doc=doc, doc=doc,
force_publishing=True, force_publishing=force_publishing,
xml_nodate=xml_nodate, xml_nodate=xml_nodate,
xml_with_decisions=xml_with_decisions, xml_with_decisions=xml_with_decisions,
) )
@ -834,9 +851,17 @@ def _formsemestre_recapcomplet_xml(
def _formsemestre_recapcomplet_json( def _formsemestre_recapcomplet_json(
context, formsemestre_id, xml_nodate, xml_with_decisions=False context,
formsemestre_id,
xml_nodate=False,
xml_with_decisions=False,
force_publishing=True,
): ):
"JSON export: liste tous les bulletins JSON" """JSON export: liste tous les bulletins JSON
:param xml_nodate(bool): indique la date courante (attribut docdate)
:param force_publishing: donne les bulletins même si non "publiés sur portail"
:returns: dict, "", "json"
"""
if xml_nodate: if xml_nodate:
docdate = "" docdate = ""
else: else:
@ -865,8 +890,27 @@ def _formsemestre_recapcomplet_json(
context, context,
formsemestre_id, formsemestre_id,
etudid, etudid,
force_publishing=True, force_publishing=force_publishing,
xml_with_decisions=xml_with_decisions, xml_with_decisions=xml_with_decisions,
) )
) )
return J, "", "json" return J, "", "json"
def formsemestres_bulletins(context, annee_scolaire, REQUEST=None):
"""Tous les bulletins des semestres publiés des semestres de l'année indiquée.
:param annee_scolaire(int): année de début de l'année scoalaire
:returns: JSON
"""
jslist = []
sems = sco_formsemestre.list_formsemestre_by_etape(
context, annee_scolaire=annee_scolaire
)
log("formsemestres_bulletins(%s): %d sems" % (annee_scolaire, len(sems)))
for sem in sems:
J, _, _ = _formsemestre_recapcomplet_json(
context, sem["formsemestre_id"], force_publishing=False
)
jslist.append(J)
return sendJSON(REQUEST, jslist)