diff --git a/README.md b/README.md
index 209a2a01766d82a2e9a501ecd01bacecd420c90d..f571216abc8bc1ce34f6db680f60d2b53a947155 100644
--- a/README.md
+++ b/README.md
@@ -20,10 +20,10 @@ Flask, SQLAlchemy, au lien de Python2/Zope dans les versions précédentes).
### État actuel (26 jan 22)
- - 9.1 (master) reproduit l'ensemble des fonctions de ScoDoc 7 (donc pas de BUT), sauf:
+ - 9.1.5x (master) reproduit l'ensemble des fonctions de ScoDoc 7 (donc pas de BUT), sauf:
- ancien module "Entreprises" (obsolète) et ajoute la gestion du BUT.
- - 9.2 (branche refactor_nt) est la version de développement.
+ - 9.2 (branche dev92) est la version de développement.
### Lignes de commandes
diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py
index 5d4fd74f34d3e946b2ef3d50b9e758e958801721..771746bf4a6fcd8332c0141018bba4f225f8cfc3 100644
--- a/app/but/bulletin_but.py
+++ b/app/but/bulletin_but.py
@@ -9,14 +9,15 @@
import datetime
from flask import url_for, g
-from app.models.formsemestre import FormSemestre
+from app.comp.res_but import ResultatsSemestreBUT
+from app.models import FormSemestre, Identite
from app.scodoc import 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_utils import fmt_note
-from app.comp.res_but import ResultatsSemestreBUT
class BulletinBUT:
@@ -28,6 +29,7 @@ class BulletinBUT:
def __init__(self, formsemestre: FormSemestre):
""" """
self.res = ResultatsSemestreBUT(formsemestre)
+ self.prefs = sco_preferences.SemPreferences(formsemestre.id)
def etud_ue_mod_results(self, etud, ue, modimpls) -> dict:
"dict synthèse résultats dans l'UE pour les modules indiqués"
@@ -84,7 +86,7 @@ class BulletinBUT:
"saes": self.etud_ue_mod_results(etud, ue, res.saes),
}
if ue.type != UE_SPORT:
- if sco_preferences.get_preference("bul_show_ue_rangs", res.formsemestre.id):
+ if self.prefs["bul_show_ue_rangs"]:
rangs, effectif = res.ue_rangs[ue.id]
rang = rangs[etud.id]
else:
@@ -155,9 +157,7 @@ class BulletinBUT:
if e.visibulletin
and (
modimpl_results.evaluations_etat[e.id].is_complete
- or sco_preferences.get_preference(
- "bul_show_all_evals", res.formsemestre.id
- )
+ or self.prefs["bul_show_all_evals"]
)
],
}
@@ -216,9 +216,11 @@ class BulletinBUT:
else:
return f"Bonus de {fmt_note(bonus_vect.iloc[0])}"
- def bulletin_etud(self, etud, formsemestre, force_publishing=False) -> dict:
- """Le bulletin de l'étudiant dans ce semestre.
- Si force_publishing, rempli le bulletin même si bul_hide_xml est vrai
+ def bulletin_etud(
+ self, etud: Identite, formsemestre, force_publishing=False
+ ) -> dict:
+ """Le bulletin de l'étudiant dans ce semestre: dict pour la version JSON / HTML.
+ - Si force_publishing, rempli le bulletin même si bul_hide_xml est vrai
(bulletins non publiés).
"""
res = self.res
@@ -239,7 +241,9 @@ class BulletinBUT:
},
"formsemestre_id": formsemestre.id,
"etat_inscription": etat_inscription,
- "options": sco_preferences.bulletin_option_affichage(formsemestre.id),
+ "options": sco_preferences.bulletin_option_affichage(
+ formsemestre.id, self.prefs
+ ),
}
if not published:
return d
@@ -312,3 +316,12 @@ class BulletinBUT:
)
return d
+
+ def bulletin_etud_complet(self, etud) -> dict:
+ """Bulletin dict complet avec toutes les infos pour les bulletins pdf"""
+ d = self.bulletin_etud(force_publishing=True)
+ d["filigranne"] = sco_bulletins_pdf.get_filigranne(
+ self.res.get_etud_etat(etud.id), self.prefs
+ )
+ # XXX TODO A COMPLETER
+ raise NotImplementedError()
diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py
index 245142484393afebdb6790c1dac38b7276a0d13a..2d491d7edcf1e5110c2900b1d0875130de871ed3 100644
--- a/app/models/formsemestre.py
+++ b/app/models/formsemestre.py
@@ -117,6 +117,7 @@ class FormSemestre(db.Model):
return f"<{self.__class__.__name__} {self.id} {self.titre_num()}>"
def to_dict(self):
+ "dict (compatible ScoDoc7)"
d = dict(self.__dict__)
d.pop("_sa_instance_state", None)
# ScoDoc7 output_formators: (backward compat)
diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py
index 93a926b64fbfb602950623a0316fa53b31160226..642841058ae30a68a8875c3e268f4960474fb749 100644
--- a/app/scodoc/sco_bulletins.py
+++ b/app/scodoc/sco_bulletins.py
@@ -28,30 +28,21 @@
"""Génération des bulletins de notes
"""
-from app.models import formsemestre
-import time
-import pprint
import email
-from email.mime.multipart import MIMEMultipart
-from email.mime.text import MIMEText
-from email.mime.base import MIMEBase
-from email.header import Header
-from reportlab.lib.colors import Color
-import urllib
+import pprint
+import time
from flask import g, request
from flask import url_for
from flask_login import current_user
from flask_mail import Message
-from app.models.moduleimpls import ModuleImplInscription
-import app.scodoc.sco_utils as scu
-from app.scodoc.sco_utils import ModuleType
-import app.scodoc.notesdb as ndb
+from app import email
from app import log
+from app.but import bulletin_but
from app.comp import res_sem
from app.comp.res_common import NotesTableCompat
-from app.models import FormSemestre
+from app.models import FormSemestre, Identite, ModuleImplInscription
from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
from app.scodoc import html_sco_header
@@ -60,9 +51,9 @@ from app.scodoc import sco_abs
from app.scodoc import sco_abs_views
from app.scodoc import sco_bulletins_generator
from app.scodoc import sco_bulletins_json
+from app.scodoc import sco_bulletins_pdf
from app.scodoc import sco_bulletins_xml
from app.scodoc import sco_codes_parcours
-from app.scodoc import sco_cache
from app.scodoc import sco_etud
from app.scodoc import sco_evaluation_db
from app.scodoc import sco_formations
@@ -73,7 +64,9 @@ from app.scodoc import sco_photos
from app.scodoc import sco_preferences
from app.scodoc import sco_pvjury
from app.scodoc import sco_users
-from app import email
+import app.scodoc.sco_utils as scu
+from app.scodoc.sco_utils import ModuleType
+import app.scodoc.notesdb as ndb
# ----- CLASSES DE BULLETINS DE NOTES
from app.scodoc import sco_bulletins_standard
@@ -190,28 +183,18 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
show_mention=prefs["bul_show_mention"],
)
- if dpv:
- I["decision_sem"] = dpv["decisions"][0]["decision_sem"]
- else:
- I["decision_sem"] = ""
I.update(infos)
I["etud_etat_html"] = _get_etud_etat_html(
formsemestre.etuds_inscriptions[etudid].etat
)
I["etud_etat"] = nt.get_etud_etat(etudid)
- I["filigranne"] = ""
+ I["filigranne"] = sco_bulletins_pdf.get_filigranne(I["etud_etat"], prefs)
I["demission"] = ""
- if I["etud_etat"] == "D":
+ if I["etud_etat"] == scu.DEMISSION:
I["demission"] = "(Démission)"
- I["filigranne"] = "Démission"
elif I["etud_etat"] == sco_codes_parcours.DEF:
I["demission"] = "(Défaillant)"
- I["filigranne"] = "Défaillant"
- elif (prefs["bul_show_temporary"] and not I["decision_sem"]) or prefs[
- "bul_show_temporary_forced"
- ]:
- I["filigranne"] = prefs["bul_temporary_txt"]
# --- Appreciations
cnx = ndb.GetDBConnexion()
@@ -687,6 +670,7 @@ def etud_descr_situation_semestre(
descr_defaillance : "Défaillant" ou vide si non défaillant.
decision_jury : "Validé", "Ajourné", ... (code semestre)
descr_decision_jury : "Décision jury: Validé" (une phrase)
+ decision_sem :
decisions_ue : noms (acronymes) des UE validées, séparées par des virgules.
descr_decisions_ue : ' UE acquises: UE1, UE2', ou vide si pas de dec. ou si pas show_uevalid
descr_mention : 'Mention Bien', ou vide si pas de mention ou si pas show_mention
@@ -696,7 +680,7 @@ def etud_descr_situation_semestre(
# --- Situation et décisions jury
- # demission/inscription ?
+ # démission/inscription ?
events = sco_etud.scolar_events_list(
cnx, args={"etudid": etudid, "formsemestre_id": formsemestre_id}
)
@@ -763,11 +747,15 @@ def etud_descr_situation_semestre(
infos["situation"] += " " + infos["descr_defaillance"]
dpv = sco_pvjury.dict_pvjury(formsemestre_id, etudids=[etudid])
+ if dpv:
+ infos["decision_sem"] = dpv["decisions"][0]["decision_sem"]
+ else:
+ infos["decision_sem"] = ""
if not show_decisions:
return infos, dpv
- # Decisions de jury:
+ # Décisions de jury:
pv = dpv["decisions"][0]
dec = ""
if pv["decision_sem_descr"]:
@@ -819,11 +807,15 @@ def formsemestre_bulletinetud(
except:
sco_etud.log_unknown_etud()
raise ScoValueError("étudiant inconnu")
- # API, donc erreurs admises en ScoValueError
- sem = sco_formsemestre.get_formsemestre(formsemestre_id, raise_soft_exc=True)
+
+ formsemestre: FormSemestre = FormSemestre.query.get(formsemestre_id)
+ if not formsemestre:
+ # API, donc erreurs admises
+ raise ScoValueError(f"semestre {formsemestre_id} inconnu !")
+ sem = formsemestre.to_dict()
bulletin = do_formsemestre_bulletinetud(
- formsemestre_id,
+ formsemestre,
etudid,
format=format,
version=version,
@@ -835,7 +827,6 @@ def formsemestre_bulletinetud(
filename = scu.bul_filename(sem, etud, format)
return scu.send_file(bulletin, filename, mime=scu.get_mime_suffix(format)[0])
- sem = sco_formsemestre.get_formsemestre(formsemestre_id)
H = [
_formsemestre_bulletinetud_header_html(
etud, etudid, sem, formsemestre_id, format, version
@@ -892,14 +883,14 @@ def can_send_bulletin_by_mail(formsemestre_id):
def do_formsemestre_bulletinetud(
- formsemestre_id,
- etudid,
+ formsemestre: FormSemestre,
+ etudid: int,
version="long", # short, long, selectedevals
format="html",
nohtml=False,
- xml_with_decisions=False, # force decisions dans XML
- force_publishing=False, # force publication meme si semestre non publie sur "portail"
- prefer_mail_perso=False, # mails envoyes sur adresse perso si non vide
+ xml_with_decisions=False, # force décisions dans XML
+ force_publishing=False, # force publication meme si semestre non publié sur "portail"
+ prefer_mail_perso=False, # mails envoyés sur adresse perso si non vide
):
"""Génère le bulletin au format demandé.
Retourne: (bul, filigranne)
@@ -908,7 +899,7 @@ def do_formsemestre_bulletinetud(
"""
if format == "xml":
bul = sco_bulletins_xml.make_xml_formsemestre_bulletinetud(
- formsemestre_id,
+ formsemestre.id,
etudid,
xml_with_decisions=xml_with_decisions,
force_publishing=force_publishing,
@@ -919,7 +910,7 @@ def do_formsemestre_bulletinetud(
elif format == "json":
bul = sco_bulletins_json.make_json_formsemestre_bulletinetud(
- formsemestre_id,
+ formsemestre.id,
etudid,
xml_with_decisions=xml_with_decisions,
force_publishing=force_publishing,
@@ -927,8 +918,13 @@ def do_formsemestre_bulletinetud(
)
return bul, ""
- I = formsemestre_bulletinetud_dict(formsemestre_id, etudid)
- etud = I["etud"]
+ if formsemestre.formation.is_apc():
+ etud = Identite.query.get(etudid)
+ r = bulletin_but.BulletinBUT(formsemestre)
+ I = r.bulletin_etud_complet(etud, formsemestre)
+ else:
+ I = formsemestre_bulletinetud_dict(formsemestre.id, etudid)
+ etud = I["etud"]
if format == "html":
htm, _ = sco_bulletins_generator.make_formsemestre_bulletinetud(
@@ -954,7 +950,7 @@ def do_formsemestre_bulletinetud(
elif format == "pdfmail":
# format pdfmail: envoie le pdf par mail a l'etud, et affiche le html
# check permission
- if not can_send_bulletin_by_mail(formsemestre_id):
+ if not can_send_bulletin_by_mail(formsemestre.id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
if nohtml:
@@ -983,7 +979,7 @@ def do_formsemestre_bulletinetud(
) + htm
return h, I["filigranne"]
#
- mail_bulletin(formsemestre_id, I, pdfdata, filename, recipient_addr)
+ mail_bulletin(formsemestre.id, I, pdfdata, filename, recipient_addr)
emaillink = '<a class="stdlink" href="mailto:%s">%s</a>' % (
recipient_addr,
recipient_addr,
diff --git a/app/scodoc/sco_bulletins_generator.py b/app/scodoc/sco_bulletins_generator.py
index 04a9efaee4c4e1413e162c9107a7fea339c4c0d6..aafdc09f69c64bd80590009aa4dddc3f37a5b03c 100644
--- a/app/scodoc/sco_bulletins_generator.py
+++ b/app/scodoc/sco_bulletins_generator.py
@@ -99,7 +99,7 @@ def bulletin_get_class_name_displayed(formsemestre_id):
return "invalide ! (voir paramètres)"
-class BulletinGenerator(object):
+class BulletinGenerator:
"Virtual superclass for PDF bulletin generators" ""
# Here some helper methods
# see sco_bulletins_standard.BulletinGeneratorStandard subclass for real methods
diff --git a/app/scodoc/sco_bulletins_pdf.py b/app/scodoc/sco_bulletins_pdf.py
index 94cfcf6bc22c0ca4e8a860c33374a7893aebc79a..748fd5a0b7d44f69ad59c4d14ebdeee61784ec9b 100644
--- a/app/scodoc/sco_bulletins_pdf.py
+++ b/app/scodoc/sco_bulletins_pdf.py
@@ -61,12 +61,10 @@ from reportlab.platypus.doctemplate import BaseDocTemplate
from flask import g, request
from app import log, ScoValueError
-from app.comp import res_sem
-from app.comp.res_common import NotesTableCompat
from app.models import FormSemestre
from app.scodoc import sco_cache
-from app.scodoc import sco_formsemestre
+from app.scodoc import sco_codes_parcours
from app.scodoc import sco_pdf
from app.scodoc import sco_preferences
from app.scodoc import sco_etud
@@ -190,7 +188,7 @@ def get_formsemestre_bulletins_pdf(formsemestre_id, version="selectedevals"):
i = 1
for etud in formsemestre.get_inscrits(include_demdef=True, order=True):
frag, filigranne = sco_bulletins.do_formsemestre_bulletinetud(
- formsemestre_id,
+ formsemestre,
etud.id,
format="pdfpart",
version=version,
@@ -239,8 +237,9 @@ def get_etud_bulletins_pdf(etudid, version="selectedevals"):
filigrannes = {}
i = 1
for sem in etud["sems"]:
+ formsemestre = FormSemestre.query.get(sem["formsemestre_id"])
frag, filigranne = sco_bulletins.do_formsemestre_bulletinetud(
- sem["formsemestre_id"],
+ formsemestre,
etudid,
format="pdfpart",
version=version,
@@ -275,3 +274,16 @@ def get_etud_bulletins_pdf(etudid, version="selectedevals"):
)
return pdfdoc, filename
+
+
+def get_filigranne(etud_etat: str, prefs) -> str:
+ """Texte à placer en "filigranne" sur le bulletin pdf"""
+ if etud_etat == scu.DEMISSION:
+ return "Démission"
+ elif etud_etat == sco_codes_parcours.DEF:
+ return "Défaillant"
+ elif (prefs["bul_show_temporary"] and not I["decision_sem"]) or prefs[
+ "bul_show_temporary_forced"
+ ]:
+ return prefs["bul_temporary_txt"]
+ return ""
diff --git a/app/scodoc/sco_preferences.py b/app/scodoc/sco_preferences.py
index b639d5ee406a4a267e2b5f8f196a3a6ca18e22c6..e0fcc53788f6851ae75d80c853607102780aa377 100644
--- a/app/scodoc/sco_preferences.py
+++ b/app/scodoc/sco_preferences.py
@@ -2114,7 +2114,7 @@ class BasePreferences(object):
return form
-class SemPreferences(object):
+class SemPreferences:
"""Preferences for a formsemestre"""
def __init__(self, formsemestre_id=None):
@@ -2270,9 +2270,8 @@ def doc_preferences():
return "\n".join([" | ".join(x) for x in L])
-def bulletin_option_affichage(formsemestre_id: int) -> dict:
+def bulletin_option_affichage(formsemestre_id: int, prefs: SemPreferences) -> dict:
"dict avec les options d'affichages (préférences) pour ce semestre"
- prefs = SemPreferences(formsemestre_id)
fields = (
"bul_show_abs",
"bul_show_abs_modules",
diff --git a/app/views/notes.py b/app/views/notes.py
index efad2808b819f6d114884e800cd1904c024f97d6..b0b812a16f81dc4021313df0ed4f12993b097304 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -1925,7 +1925,7 @@ def formsemestre_bulletins_mailetuds(
nb_send = 0
for etudid in etudids:
h, _ = sco_bulletins.do_formsemestre_bulletinetud(
- formsemestre_id,
+ formsemestre,
etudid,
version=version,
prefer_mail_perso=prefer_mail_perso,
diff --git a/sco_version.py b/sco_version.py
index 23fba00697c6fb99cf55c067f3fd0eb29848633d..035ab07f290463fddd66590734195d5a5dcf723d 100644
--- a/sco_version.py
+++ b/sco_version.py
@@ -1,7 +1,7 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
-SCOVERSION = "9.1.56"
+SCOVERSION = "9.2a-57"
SCONAME = "ScoDoc"