Infos pour bulletins BUT pdf

This commit is contained in:
Emmanuel Viennet 2022-03-05 12:47:08 +01:00
parent ec9cdfe50a
commit c923a5015b
9 changed files with 134 additions and 115 deletions

View File

@ -16,7 +16,7 @@ from app.scodoc import sco_bulletins, sco_utils as scu
from app.scodoc import sco_bulletins_json
from app.scodoc import sco_bulletins_pdf
from app.scodoc import sco_preferences
from app.scodoc.sco_codes_parcours import UE_SPORT
from app.scodoc.sco_codes_parcours import UE_SPORT, DEF
from app.scodoc.sco_utils import fmt_note
@ -318,19 +318,42 @@ class BulletinBUT:
return d
def bulletin_etud_complet(self, etud: Identite) -> dict:
"""Bulletin dict complet avec toutes les infos pour les bulletins pdf"""
"""Bulletin dict complet avec toutes les infos pour les bulletins BUT pdf
Résultat compatible avec celui de sco_bulletins.formsemestre_bulletinetud_dict
"""
d = self.bulletin_etud(etud, self.res.formsemestre, force_publishing=True)
d["etudid"] = etud.id
d["etud"] = d["etudiant"]
d["etud"]["nomprenom"] = etud.nomprenom
d.update(self.res.sem)
etud_etat = self.res.get_etud_etat(etud.id)
d["filigranne"] = sco_bulletins_pdf.get_filigranne(
self.res.get_etud_etat(etud.id),
etud_etat,
self.prefs,
decision_sem=d["semestre"].get("decision_sem"),
)
if etud_etat == scu.DEMISSION:
d["demission"] = "(Démission)"
elif etud_etat == DEF:
d["demission"] = "(Défaillant)"
else:
d["demission"] = ""
# --- Absences
d["nbabs"], d["nbabsjust"] = self.res.formsemestre.get_abs_count(etud.id)
# --- Decision Jury
infos, dpv = sco_bulletins.etud_descr_situation_semestre(
etud.id,
self.res.formsemestre.id,
format="html",
show_date_inscr=self.prefs["bul_show_date_inscr"],
show_decisions=self.prefs["bul_show_decision"],
show_uevalid=self.prefs["bul_show_uevalid"],
show_mention=self.prefs["bul_show_mention"],
)
d.update(infos)
# --- Rangs
d[
"rang_nt"
@ -341,5 +364,6 @@ class BulletinBUT:
d.update(
sco_bulletins.get_appreciations_list(self.res.formsemestre.id, etud.id)
)
# XXX TODO A COMPLETER ?
d.update(sco_bulletins.make_context_dict(self.res.formsemestre, d["etud"]))
return d

View File

@ -35,6 +35,7 @@ import datetime
from flask import g, url_for
from flask_mail import Message
from app.models.formsemestre import FormSemestre
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
@ -55,27 +56,30 @@ def abs_notify(etudid, date):
"""
from app.scodoc import sco_abs
sem = retreive_current_formsemestre(etudid, date)
if not sem:
formsemestre = retreive_current_formsemestre(etudid, date)
if not formsemestre:
return # non inscrit a la date, pas de notification
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
do_abs_notify(sem, etudid, date, nbabs, nbabsjust)
nbabs, nbabsjust = sco_abs.get_abs_count_in_interval(
etudid, formsemestre.date_debut.isoformat(), formsemestre.date_fin.isoformat()
)
do_abs_notify(formsemestre, etudid, date, nbabs, nbabsjust)
def do_abs_notify(sem, etudid, date, nbabs, nbabsjust):
def do_abs_notify(formsemestre: FormSemestre, etudid, date, nbabs, nbabsjust):
"""Given new counts of absences, check if notifications are requested and send them."""
# prefs fallback to global pref if sem is None:
if sem:
formsemestre_id = sem["formsemestre_id"]
if formsemestre:
formsemestre_id = formsemestre.id
else:
formsemestre_id = None
prefs = sco_preferences.SemPreferences(formsemestre_id=sem["formsemestre_id"])
prefs = sco_preferences.SemPreferences(formsemestre_id=formsemestre_id)
destinations = abs_notify_get_destinations(
sem, prefs, etudid, date, nbabs, nbabsjust
formsemestre, prefs, etudid, date, nbabs, nbabsjust
)
msg = abs_notification_message(sem, prefs, etudid, nbabs, nbabsjust)
msg = abs_notification_message(formsemestre, prefs, etudid, nbabs, nbabsjust)
if not msg:
return # abort
@ -131,19 +135,19 @@ def abs_notify_send(destinations, etudid, msg, nbabs, nbabsjust, formsemestre_id
)
def abs_notify_get_destinations(sem, prefs, etudid, date, nbabs, nbabsjust):
def abs_notify_get_destinations(
formsemestre: FormSemestre, prefs, etudid, date, nbabs, nbabsjust
) -> set:
"""Returns set of destination emails to be notified"""
formsemestre_id = sem["formsemestre_id"]
destinations = [] # list of email address to notify
if abs_notify_is_above_threshold(etudid, nbabs, nbabsjust, formsemestre_id):
if sem and prefs["abs_notify_respsem"]:
if abs_notify_is_above_threshold(etudid, nbabs, nbabsjust, formsemestre.id):
if prefs["abs_notify_respsem"]:
# notifie chaque responsable du semestre
for responsable_id in sem["responsables"]:
u = sco_users.user_info(responsable_id)
if u["email"]:
destinations.append(u["email"])
for responsable in formsemestre.responsables:
if responsable.email:
destinations.append(responsable.email)
if prefs["abs_notify_chief"] and prefs["email_chefdpt"]:
destinations.append(prefs["email_chefdpt"])
if prefs["abs_notify_email"]:
@ -156,7 +160,7 @@ def abs_notify_get_destinations(sem, prefs, etudid, date, nbabs, nbabsjust):
# Notification (à chaque fois) des resp. de modules ayant des évaluations
# à cette date
# nb: on pourrait prevoir d'utiliser un autre format de message pour ce cas
if sem and prefs["abs_notify_respeval"]:
if prefs["abs_notify_respeval"]:
mods = mod_with_evals_at_date(date, etudid)
for mod in mods:
u = sco_users.user_info(mod["responsable_id"])
@ -232,7 +236,9 @@ def user_nbdays_since_last_notif(email_addr, etudid):
return None
def abs_notification_message(sem, prefs, etudid, nbabs, nbabsjust):
def abs_notification_message(
formsemestre: FormSemestre, prefs, etudid, nbabs, nbabsjust
):
"""Mime notification message based on template.
returns a Message instance
or None if sending should be canceled (empty template).
@ -242,7 +248,7 @@ def abs_notification_message(sem, prefs, etudid, nbabs, nbabsjust):
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
# Variables accessibles dans les balises du template: %(nom_variable)s :
values = sco_bulletins.make_context_dict(sem, etud)
values = sco_bulletins.make_context_dict(formsemestre, etud)
values["nbabs"] = nbabs
values["nbabsjust"] = nbabsjust
@ -264,9 +270,11 @@ def abs_notification_message(sem, prefs, etudid, nbabs, nbabsjust):
return msg
def retreive_current_formsemestre(etudid, cur_date):
def retreive_current_formsemestre(etudid: int, cur_date) -> FormSemestre:
"""Get formsemestre dans lequel etudid est (ou était) inscrit a la date indiquée
date est une chaine au format ISO (yyyy-mm-dd)
Result: FormSemestre ou None si pas inscrit à la date indiquée
"""
req = """SELECT i.formsemestre_id
FROM notes_formsemestre_inscription i, notes_formsemestre sem
@ -278,8 +286,8 @@ def retreive_current_formsemestre(etudid, cur_date):
if not r:
return None
# s'il y a plusieurs semestres, prend le premier (rarissime et non significatif):
sem = sco_formsemestre.get_formsemestre(r[0]["formsemestre_id"])
return sem
formsemestre = FormSemestre.query.get(r[0]["formsemestre_id"])
return formsemestre
def mod_with_evals_at_date(date_abs, etudid):

View File

@ -78,33 +78,20 @@ from app.scodoc import sco_bulletins_legacy
from app.scodoc import sco_bulletins_ucac # format expérimental UCAC Cameroun
def make_context_dict(sem, etud):
def make_context_dict(formsemestre: FormSemestre, etud: dict) -> dict:
"""Construit dictionnaire avec valeurs pour substitution des textes
(preferences bul_pdf_*)
"""
C = sem.copy()
C["responsable"] = " ,".join(
[
sco_users.user_info(responsable_id)["prenomnom"]
for responsable_id in sem["responsables"]
]
)
annee_debut = sem["date_debut"].split("/")[2]
annee_fin = sem["date_fin"].split("/")[2]
if annee_debut != annee_fin:
annee = "%s - %s" % (annee_debut, annee_fin)
else:
annee = annee_debut
C["anneesem"] = annee
C = formsemestre.get_infos_dict()
C["responsable"] = formsemestre.responsables_str()
C["anneesem"] = C["annee"] # backward compat
C.update(etud)
# copie preferences
# XXX devrait acceder directement à un dict de preferences, à revoir
for name in sco_preferences.get_base_preferences().prefs_name:
C[name] = sco_preferences.get_preference(name, sem["formsemestre_id"])
C[name] = sco_preferences.get_preference(name, formsemestre.id)
# ajoute groupes et group_0, group_1, ...
sco_groups.etud_add_group_infos(etud, sem)
sco_groups.etud_add_group_infos(etud, formsemestre.id)
C["groupes"] = etud["groupes"]
n = 0
for partition_id in etud["partitions"]:
@ -125,7 +112,8 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
Le contenu du dictionnaire dépend des options (rangs, ...)
et de la version choisie (short, long, selectedevals).
Cette fonction est utilisée pour les bulletins HTML et PDF, mais pas ceux en XML.
Cette fonction est utilisée pour les bulletins CLASSIQUES (DUT, ...)
en HTML et PDF, mais pas ceux en XML.
"""
from app.scodoc import sco_abs
@ -190,7 +178,7 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
)
I["etud_etat"] = nt.get_etud_etat(etudid)
I["filigranne"] = sco_bulletins_pdf.get_filigranne(
I["etud_etat"], prefs, decision_dem=I["decision_sem"]
I["etud_etat"], prefs, decision_sem=I["decision_sem"]
)
I["demission"] = ""
if I["etud_etat"] == scu.DEMISSION:
@ -384,7 +372,7 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
I["matieres_modules"].update(_sort_mod_by_matiere(modules, nt, etudid))
#
C = make_context_dict(I["sem"], I["etud"])
C = make_context_dict(formsemestre, I["etud"])
C.update(I)
#
# log( 'C = \n%s\n' % pprint.pformat(C) ) # tres pratique pour voir toutes les infos dispo
@ -842,7 +830,7 @@ def formsemestre_bulletinetud(
H = [
_formsemestre_bulletinetud_header_html(
etud, etudid, sem, formsemestre_id, format, version
etud, etudid, formsemestre, format, version
),
bulletin,
]
@ -1063,8 +1051,7 @@ def mail_bulletin(formsemestre_id, I, pdfdata, filename, recipient_addr):
def _formsemestre_bulletinetud_header_html(
etud,
etudid,
sem,
formsemestre_id=None,
formsemestre: FormSemestre,
format=None,
version=None,
):
@ -1078,33 +1065,27 @@ def _formsemestre_bulletinetud_header_html(
],
cssstyles=["css/radar_bulletin.css"],
),
"""<table class="bull_head"><tr><td>
<h2><a class="discretelink" href="%s">%s</a></h2>
"""
% (
f"""<table class="bull_head"><tr><td>
<h2><a class="discretelink" href="{
url_for(
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"]
),
etud["nomprenom"],
),
"""
<form name="f" method="GET" action="%s">"""
% request.base_url,
f"""Bulletin <span class="bull_liensemestre"><a href="{
url_for("notes.formsemestre_status",
scodoc_dept=g.scodoc_dept,
formsemestre_id=sem["formsemestre_id"])}
">{sem["titremois"]}</a></span>
<br/>"""
% sem,
"""<table><tr>""",
"""<td>établi le %s (notes sur 20)</td>""" % time.strftime("%d/%m/%Y à %Hh%M"),
"""<td><span class="rightjust">
<input type="hidden" name="formsemestre_id" value="%s"></input>"""
% formsemestre_id,
"""<input type="hidden" name="etudid" value="%s"></input>""" % etudid,
"""<input type="hidden" name="format" value="%s"></input>""" % format,
"""<select name="version" onchange="document.f.submit()" class="noprint">""",
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"]
)}">{etud["nomprenom"]}</a></h2>
<form name="f" method="GET" action="{request.base_url}">
Bulletin <span class="bull_liensemestre"><a href="{
url_for("notes.formsemestre_status",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id)}
">{formsemestre.titre_mois()}</a></span>
<br/>
<table><tr>
<td>établi le {time.strftime("%d/%m/%Y à %Hh%M")} (notes sur 20)</td>
<td><span class="rightjust">
<input type="hidden" name="formsemestre_id" value="{formsemestre.id}"></input>
<input type="hidden" name="etudid" value="{etudid}"></input>
<input type="hidden" name="format" value="{format}"></input>
<select name="version" onchange="document.f.submit()" class="noprint">
""",
]
for (v, e) in (
("short", "Version courte"),
@ -1125,7 +1106,7 @@ def _formsemestre_bulletinetud_header_html(
"title": "Réglages bulletins",
"endpoint": "notes.formsemestre_edit_options",
"args": {
"formsemestre_id": formsemestre_id,
"formsemestre_id": formsemestre.id,
# "target_url": url_for(
# "notes.formsemestre_bulletinetud",
# scodoc_dept=g.scodoc_dept,
@ -1133,17 +1114,16 @@ def _formsemestre_bulletinetud_header_html(
# etudid=etudid,
# ),
},
"enabled": (current_user.id in sem["responsables"])
or current_user.has_permission(Permission.ScoImplement),
"enabled": formsemestre.can_be_edited_by(current_user),
},
{
"title": 'Version papier (pdf, format "%s")'
% sco_bulletins_generator.bulletin_get_class_name_displayed(
formsemestre_id
formsemestre.id
),
"endpoint": endpoint,
"args": {
"formsemestre_id": formsemestre_id,
"formsemestre_id": formsemestre.id,
"etudid": etudid,
"version": version,
"format": "pdf",
@ -1153,19 +1133,19 @@ def _formsemestre_bulletinetud_header_html(
"title": "Envoi par mail à %s" % etud["email"],
"endpoint": endpoint,
"args": {
"formsemestre_id": formsemestre_id,
"formsemestre_id": formsemestre.id,
"etudid": etudid,
"version": version,
"format": "pdfmail",
},
# possible slt si on a un mail...
"enabled": etud["email"] and can_send_bulletin_by_mail(formsemestre_id),
"enabled": etud["email"] and can_send_bulletin_by_mail(formsemestre.id),
},
{
"title": "Envoi par mail à %s (adr. personnelle)" % etud["emailperso"],
"endpoint": endpoint,
"args": {
"formsemestre_id": formsemestre_id,
"formsemestre_id": formsemestre.id,
"etudid": etudid,
"version": version,
"format": "pdfmail",
@ -1173,13 +1153,13 @@ def _formsemestre_bulletinetud_header_html(
},
# possible slt si on a un mail...
"enabled": etud["emailperso"]
and can_send_bulletin_by_mail(formsemestre_id),
and can_send_bulletin_by_mail(formsemestre.id),
},
{
"title": "Version json",
"endpoint": endpoint,
"args": {
"formsemestre_id": formsemestre_id,
"formsemestre_id": formsemestre.id,
"etudid": etudid,
"version": version,
"format": "json",
@ -1189,7 +1169,7 @@ def _formsemestre_bulletinetud_header_html(
"title": "Version XML",
"endpoint": endpoint,
"args": {
"formsemestre_id": formsemestre_id,
"formsemestre_id": formsemestre.id,
"etudid": etudid,
"version": version,
"format": "xml",
@ -1199,19 +1179,19 @@ def _formsemestre_bulletinetud_header_html(
"title": "Ajouter une appréciation",
"endpoint": "notes.appreciation_add_form",
"args": {
"formsemestre_id": formsemestre_id,
"formsemestre_id": formsemestre.id,
"etudid": etudid,
},
"enabled": (
(current_user.id in sem["responsables"])
or (current_user.has_permission(Permission.ScoEtudInscrit))
formsemestre.can_be_edited_by(current_user)
or current_user.has_permission(Permission.ScoEtudInscrit)
),
},
{
"title": "Enregistrer un semestre effectué ailleurs",
"endpoint": "notes.formsemestre_ext_create_form",
"args": {
"formsemestre_id": formsemestre_id,
"formsemestre_id": formsemestre.id,
"etudid": etudid,
},
"enabled": current_user.has_permission(Permission.ScoImplement),
@ -1220,34 +1200,34 @@ def _formsemestre_bulletinetud_header_html(
"title": "Enregistrer une validation d'UE antérieure",
"endpoint": "notes.formsemestre_validate_previous_ue",
"args": {
"formsemestre_id": formsemestre_id,
"formsemestre_id": formsemestre.id,
"etudid": etudid,
},
"enabled": sco_permissions_check.can_validate_sem(formsemestre_id),
"enabled": sco_permissions_check.can_validate_sem(formsemestre.id),
},
{
"title": "Enregistrer note d'une UE externe",
"endpoint": "notes.external_ue_create_form",
"args": {
"formsemestre_id": formsemestre_id,
"formsemestre_id": formsemestre.id,
"etudid": etudid,
},
"enabled": sco_permissions_check.can_validate_sem(formsemestre_id),
"enabled": sco_permissions_check.can_validate_sem(formsemestre.id),
},
{
"title": "Entrer décisions jury",
"endpoint": "notes.formsemestre_validation_etud_form",
"args": {
"formsemestre_id": formsemestre_id,
"formsemestre_id": formsemestre.id,
"etudid": etudid,
},
"enabled": sco_permissions_check.can_validate_sem(formsemestre_id),
"enabled": sco_permissions_check.can_validate_sem(formsemestre.id),
},
{
"title": "Editer PV jury",
"endpoint": "notes.formsemestre_pvjury_pdf",
"args": {
"formsemestre_id": formsemestre_id,
"formsemestre_id": formsemestre.id,
"etudid": etudid,
},
"enabled": True,
@ -1263,7 +1243,7 @@ def _formsemestre_bulletinetud_header_html(
url_for(
"notes.formsemestre_bulletinetud",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
formsemestre_id=formsemestre.id,
etudid=etudid,
format="pdf",
version=version,

View File

@ -180,7 +180,9 @@ def search_etud_in_dept(expnom=""):
e["_nomprenom_target"] = target
e["inscription_target"] = target
e["_nomprenom_td_attrs"] = 'id="%s" class="etudinfo"' % (e["etudid"])
sco_groups.etud_add_group_infos(e, e["cursem"])
sco_groups.etud_add_group_infos(
e, e["cursem"]["formsemestre_id"] if e["cursem"] else None
)
tab = GenTable(
columns_ids=("nomprenom", "code_nip", "inscription", "groupes"),

View File

@ -321,7 +321,7 @@ def get_group_infos(group_id, etat=None): # was _getlisteetud
t["etath"] = t["etat"]
# Add membership for all partitions, 'partition_id' : group
for etud in members: # long: comment eviter ces boucles ?
etud_add_group_infos(etud, sem)
etud_add_group_infos(etud, sem["formsemestre_id"])
if group["group_name"] != None:
group_tit = "%s %s" % (group["partition_name"], group["group_name"])
@ -413,12 +413,12 @@ def formsemestre_get_etud_groupnames(formsemestre_id, attr="group_name"):
return R
def etud_add_group_infos(etud, sem, sep=" "):
def etud_add_group_infos(etud, formsemestre_id, sep=" "):
"""Add informations on partitions and group memberships to etud (a dict with an etudid)"""
etud[
"partitions"
] = collections.OrderedDict() # partition_id : group + partition_name
if not sem:
if not formsemestre_id:
etud["groupes"] = ""
return etud
@ -430,7 +430,7 @@ def etud_add_group_infos(etud, sem, sep=" "):
and p.formsemestre_id = %(formsemestre_id)s
ORDER BY p.numero
""",
{"etudid": etud["etudid"], "formsemestre_id": sem["formsemestre_id"]},
{"etudid": etud["etudid"], "formsemestre_id": formsemestre_id},
)
for info in infos:
@ -439,13 +439,13 @@ def etud_add_group_infos(etud, sem, sep=" "):
# resume textuel des groupes:
etud["groupes"] = sep.join(
[g["group_name"] for g in infos if g["group_name"] != None]
[gr["group_name"] for gr in infos if gr["group_name"] is not None]
)
etud["partitionsgroupes"] = sep.join(
[
g["partition_name"] + ":" + g["group_name"]
for g in infos
if g["group_name"] != None
gr["partition_name"] + ":" + gr["group_name"]
for gr in infos
if gr["group_name"] is not None
]
)

View File

@ -203,7 +203,7 @@ def sco_import_generate_excel_sample(
for field in titles:
if field == "groupes":
sco_groups.etud_add_group_infos(
etud, groups_infos.formsemestre, sep=";"
etud, groups_infos.formsemestre_id, sep=";"
)
l.append(etud["partitionsgroupes"])
else:

View File

@ -196,7 +196,10 @@ def do_inscrit(sem, etudids, inscrit_groupes=False):
if len(etud["sems"]) < 2:
continue
prev_formsemestre = etud["sems"][1]
sco_groups.etud_add_group_infos(etud, prev_formsemestre)
sco_groups.etud_add_group_infos(
etud,
prev_formsemestre["formsemestre_id"] if prev_formsemestre else None,
)
cursem_groups_by_name = dict(
[

View File

@ -215,7 +215,9 @@ def ficheEtud(etudid=None):
info["modifadresse"] = ""
# Groupes:
sco_groups.etud_add_group_infos(info, info["cursem"])
sco_groups.etud_add_group_infos(
info, info["cursem"]["formsemestre_id"] if info["cursem"] else None
)
# Parcours de l'étudiant
if info["sems"]:

View File

@ -513,7 +513,7 @@ def etud_info(etudid=None, format="xml"):
sem = etud["cursem"]
if sem:
sco_groups.etud_add_group_infos(etud, sem)
sco_groups.etud_add_group_infos(etud, sem["formsemestre_id"] if sem else None)
d["insemestre"] = [
{
"current": "1",