modernisation/methodes sur Identite/bul. head.

This commit is contained in:
Emmanuel Viennet 2022-03-06 22:40:20 +01:00
parent c923a5015b
commit 8f911234b2
14 changed files with 334 additions and 107 deletions

View File

@ -224,7 +224,7 @@ class BulletinBUT:
(bulletins non publiés). (bulletins non publiés).
""" """
res = self.res res = self.res
etat_inscription = etud.etat_inscription(formsemestre.id) etat_inscription = etud.inscription_etat(formsemestre.id)
nb_inscrits = self.res.get_inscriptions_counts()[scu.INSCRIT] nb_inscrits = self.res.get_inscriptions_counts()[scu.INSCRIT]
published = (not formsemestre.bul_hide_xml) or force_publishing published = (not formsemestre.bul_hide_xml) or force_publishing
d = { d = {

View File

@ -72,7 +72,7 @@ def bulletin_but_xml_compat(
etud: Identite = Identite.query.get_or_404(etudid) etud: Identite = Identite.query.get_or_404(etudid)
results = bulletin_but.ResultatsSemestreBUT(formsemestre) results = bulletin_but.ResultatsSemestreBUT(formsemestre)
nb_inscrits = results.get_inscriptions_counts()[scu.INSCRIT] nb_inscrits = results.get_inscriptions_counts()[scu.INSCRIT]
# etat_inscription = etud.etat_inscription(formsemestre.id) # etat_inscription = etud.inscription_etat(formsemestre.id)
etat_inscription = results.formsemestre.etuds_inscriptions[etudid].etat etat_inscription = results.formsemestre.etuds_inscriptions[etudid].etat
if (not formsemestre.bul_hide_xml) or force_publishing: if (not formsemestre.bul_hide_xml) or force_publishing:
published = 1 published = 1

View File

@ -4,12 +4,14 @@
et données rattachées (adresses, annotations, ...) et données rattachées (adresses, annotations, ...)
""" """
import datetime
from functools import cached_property from functools import cached_property
from flask import abort, url_for from flask import abort, url_for
from flask import g, request from flask import g, request
import sqlalchemy import sqlalchemy
from sqlalchemy import desc, text
from app import db from app import db, log
from app import models from app import models
from app.scodoc import notesdb as ndb from app.scodoc import notesdb as ndb
@ -82,6 +84,11 @@ class Identite(db.Model):
return scu.suppress_accents(s) return scu.suppress_accents(s)
return s return s
@property
def e(self):
"terminaison en français: 'ne', '', 'ou '(e)'"
return {"M": "", "F": "e"}.get(self.civilite, "(e)")
def nom_disp(self) -> str: def nom_disp(self) -> str:
"Nom à afficher" "Nom à afficher"
if self.nom_usuel: if self.nom_usuel:
@ -123,7 +130,7 @@ class Identite(db.Model):
def get_first_email(self, field="email") -> str: def get_first_email(self, field="email") -> str:
"Le mail associé à la première adrese de l'étudiant, ou None" "Le mail associé à la première adrese de l'étudiant, ou None"
return self.adresses[0].email or None if self.adresses.count() > 0 else None return getattr(self.adresses[0], field) if self.adresses.count() > 0 else None
def to_dict_scodoc7(self): def to_dict_scodoc7(self):
"""Représentation dictionnaire, """Représentation dictionnaire,
@ -134,7 +141,7 @@ class Identite(db.Model):
# ScoDoc7 output_formators: (backward compat) # ScoDoc7 output_formators: (backward compat)
e["etudid"] = self.id e["etudid"] = self.id
e["date_naissance"] = ndb.DateISOtoDMY(e["date_naissance"]) e["date_naissance"] = ndb.DateISOtoDMY(e["date_naissance"])
e["ne"] = {"M": "", "F": "ne"}.get(self.civilite, "(e)") e["ne"] = self.e
return {k: e[k] or "" for k in e} # convert_null_outputs_to_empty return {k: e[k] or "" for k in e} # convert_null_outputs_to_empty
def to_dict_bul(self, include_urls=True): def to_dict_bul(self, include_urls=True):
@ -172,6 +179,23 @@ class Identite(db.Model):
] ]
return r[0] if r else None return r[0] if r else None
def inscriptions_courantes(self) -> list: # -> list[FormSemestreInscription]:
"""Liste des inscriptions à des semestres _courants_
(il est rare qu'il y en ai plus d'une, mais c'est possible).
Triées par date de début de semestre décroissante (le plus récent en premier).
"""
from app.models.formsemestre import FormSemestre, FormSemestreInscription
return (
FormSemestreInscription.query.join(FormSemestreInscription.formsemestre)
.filter(
FormSemestreInscription.etudid == self.id,
text("date_debut < now() and date_fin > now()"),
)
.order_by(desc(FormSemestre.date_debut))
.all()
)
def inscription_courante_date(self, date_debut, date_fin): def inscription_courante_date(self, date_debut, date_fin):
"""La première inscription à un formsemestre incluant la """La première inscription à un formsemestre incluant la
période [date_debut, date_fin] période [date_debut, date_fin]
@ -183,8 +207,8 @@ class Identite(db.Model):
] ]
return r[0] if r else None return r[0] if r else None
def etat_inscription(self, formsemestre_id): def inscription_etat(self, formsemestre_id):
"""etat de l'inscription de cet étudiant au semestre: """État de l'inscription de cet étudiant au semestre:
False si pas inscrit, ou scu.INSCRIT, DEMISSION, DEF False si pas inscrit, ou scu.INSCRIT, DEMISSION, DEF
""" """
# voir si ce n'est pas trop lent: # voir si ce n'est pas trop lent:
@ -195,6 +219,110 @@ class Identite(db.Model):
return ins.etat return ins.etat
return False return False
def inscription_descr(self) -> dict:
"""Description de l'état d'inscription"""
inscription_courante = self.inscription_courante()
if inscription_courante:
titre_sem = inscription_courante.formsemestre.titre_mois()
return {
"etat_in_cursem": inscription_courante.etat,
"inscription_courante": inscription_courante,
"inscription": titre_sem,
"inscription_str": "Inscrit en " + titre_sem,
"situation": self.descr_situation_etud(),
}
else:
if self.formsemestre_inscriptions:
# cherche l'inscription la plus récente:
fin_dernier_sem = max(
[
inscr.formsemestre.date_debut
for inscr in self.formsemestre_inscriptions
]
)
if fin_dernier_sem > datetime.date.today():
inscription = "futur"
situation = "futur élève"
else:
inscription = "ancien"
situation = "ancien élève"
else:
inscription = ("non inscrit",)
situation = inscription
return {
"etat_in_cursem": "?",
"inscription_courante": None,
"inscription": inscription,
"inscription_str": inscription,
"situation": situation,
}
def descr_situation_etud(self) -> str:
"""Chaîne décrivant la situation _actuelle_ de l'étudiant.
Exemple:
"inscrit en BUT R&T semestre 2 FI (Jan 2022 - Jul 2022) le 16/01/2022"
ou
"non inscrit"
"""
inscriptions_courantes = self.inscriptions_courantes()
if inscriptions_courantes:
inscr = inscriptions_courantes[0]
if inscr.etat == scu.INSCRIT:
situation = f"inscrit{self.e} en {inscr.formsemestre.titre_mois()}"
# Cherche la date d'inscription dans scolar_events:
events = models.ScolarEvent.query.filter_by(
etudid=self.id,
formsemestre_id=inscr.formsemestre.id,
event_type="INSCRIPTION",
).all()
if not events:
log(
f"*** situation inconsistante pour {self} (inscrit mais pas d'event)"
)
date_ins = "???" # ???
else:
date_ins = events[0].event_date
situation += date_ins.strftime(" le %d/%m/%Y")
else:
situation = f"démission de {inscr.formsemestre.titre_mois()}"
# Cherche la date de demission dans scolar_events:
events = models.ScolarEvent.query.filter_by(
etudid=self.id,
formsemestre_id=inscr.formsemestre.id,
event_type="DEMISSION",
).all()
if not events:
log(
f"*** situation inconsistante pour {self} (demission mais pas d'event)"
)
date_dem = "???" # ???
else:
date_dem = events[0].event_date
situation += date_dem.strftime(" le %d/%m/%Y")
else:
situation = "non inscrit" + self.e
return situation
def photo_html(self, title=None, size="small") -> str:
"""HTML img tag for the photo, either in small size (h90)
or original size (size=="orig")
"""
from app.scodoc import sco_photos
# sco_photo traite des dicts:
return sco_photos.etud_photo_html(
etud=dict(
etudid=self.id,
code_nip=self.code_nip,
nomprenom=self.nomprenom,
nom_disp=self.nom_disp(),
photo_filename=self.photo_filename,
),
title=title,
size=size,
)
def make_etud_args( def make_etud_args(
etudid=None, code_nip=None, use_request=True, raise_exc=False, abort_404=True etudid=None, code_nip=None, use_request=True, raise_exc=False, abort_404=True

View File

@ -12,7 +12,6 @@ from app import log
from app.models import APO_CODE_STR_LEN from app.models import APO_CODE_STR_LEN
from app.models import SHORT_STR_LEN from app.models import SHORT_STR_LEN
from app.models import CODE_STR_LEN from app.models import CODE_STR_LEN
from app.models import UniteEns
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.models.ues import UniteEns from app.models.ues import UniteEns

View File

@ -6,7 +6,8 @@ import flask_sqlalchemy
from app import db from app import db
from app.comp import df_cache from app.comp import df_cache
from app.models import Identite, Module from app.models.etudiants import Identite
from app.models.modules import Module
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu

View File

@ -29,13 +29,11 @@
""" """
import email import email
import pprint
import time import time
from flask import g, request from flask import g, request
from flask import url_for from flask import render_template, url_for
from flask_login import current_user from flask_login import current_user
from flask_mail import Message
from app import email from app import email
from app import log from app import log
@ -802,18 +800,10 @@ def formsemestre_bulletinetud(
prefer_mail_perso=False, prefer_mail_perso=False,
): ):
"page bulletin de notes" "page bulletin de notes"
try: etud: Identite = Identite.query.get_or_404(etudid)
etud = sco_etud.get_etud_info(filled=True)[0]
etudid = etud["etudid"]
except:
sco_etud.log_unknown_etud()
raise ScoValueError("étudiant inconnu")
formsemestre: FormSemestre = FormSemestre.query.get(formsemestre_id) formsemestre: FormSemestre = FormSemestre.query.get(formsemestre_id)
if not formsemestre: if not formsemestre:
# API, donc erreurs admises
raise ScoValueError(f"semestre {formsemestre_id} inconnu !") raise ScoValueError(f"semestre {formsemestre_id} inconnu !")
sem = formsemestre.to_dict()
bulletin = do_formsemestre_bulletinetud( bulletin = do_formsemestre_bulletinetud(
formsemestre, formsemestre,
@ -825,37 +815,39 @@ def formsemestre_bulletinetud(
prefer_mail_perso=prefer_mail_perso, prefer_mail_perso=prefer_mail_perso,
)[0] )[0]
if format not in {"html", "pdfmail"}: if format not in {"html", "pdfmail"}:
filename = scu.bul_filename(sem, etud, format) filename = scu.bul_filename(formsemestre, etud, format)
return scu.send_file(bulletin, filename, mime=scu.get_mime_suffix(format)[0]) return scu.send_file(bulletin, filename, mime=scu.get_mime_suffix(format)[0])
H = [ H = [
_formsemestre_bulletinetud_header_html( _formsemestre_bulletinetud_header_html(etud, formsemestre, format, version),
etud, etudid, formsemestre, format, version
),
bulletin, bulletin,
] ]
H.append("""<p>Situation actuelle: """) H.append("""<p>Situation actuelle: """)
if etud["inscription_formsemestre_id"]: inscription_courante = etud.inscription_courante()
if inscription_courante:
H.append( H.append(
f"""<a class="stdlink" href="{url_for( f"""<a class="stdlink" href="{url_for(
"notes.formsemestre_status", "notes.formsemestre_status",
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
formsemestre_id=etud["inscription_formsemestre_id"]) formsemestre_id=inscription_courante.formsemestre_id)
}">""" }">"""
) )
H.append(etud["inscriptionstr"]) inscription_descr = etud.inscription_descr()
if etud["inscription_formsemestre_id"]: H.append(inscription_descr["inscription_str"])
if inscription_courante:
H.append("""</a>""") H.append("""</a>""")
H.append("""</p>""") H.append("""</p>""")
if sem["modalite"] == "EXT": if formsemestre.modalite == "EXT":
H.append( H.append(
"""<p><a f"""<p><a
href="formsemestre_ext_edit_ue_validations?formsemestre_id=%s&etudid=%s" href="{url_for('notes.formsemestre_ext_edit_ue_validations',
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
etudid=etudid)}"
class="stdlink"> class="stdlink">
Editer les validations d'UE dans ce semestre extérieur Éditer les validations d'UE dans ce semestre extérieur
</a></p>""" </a></p>"""
% (formsemestre_id, etudid)
) )
# Place du diagramme radar # Place du diagramme radar
H.append( H.append(
@ -1048,16 +1040,15 @@ def mail_bulletin(formsemestre_id, I, pdfdata, filename, recipient_addr):
) )
def _formsemestre_bulletinetud_header_html( def _formsemestre_bulletinetud_header_html_old_XXX(
etud, etud: Identite,
etudid,
formsemestre: FormSemestre, formsemestre: FormSemestre,
format=None, format=None,
version=None, version=None,
): ):
H = [ H = [
html_sco_header.sco_header( html_sco_header.sco_header(
page_title="Bulletin de %(nomprenom)s" % etud, page_title=f"Bulletin de {etud.nomprenom}",
javascripts=[ javascripts=[
"js/bulletin.js", "js/bulletin.js",
"libjs/d3.v3.min.js", "libjs/d3.v3.min.js",
@ -1068,8 +1059,8 @@ def _formsemestre_bulletinetud_header_html(
f"""<table class="bull_head"><tr><td> f"""<table class="bull_head"><tr><td>
<h2><a class="discretelink" href="{ <h2><a class="discretelink" href="{
url_for( url_for(
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"] "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id
)}">{etud["nomprenom"]}</a></h2> )}">{etud.nomprenom}</a></h2>
<form name="f" method="GET" action="{request.base_url}"> <form name="f" method="GET" action="{request.base_url}">
Bulletin <span class="bull_liensemestre"><a href="{ Bulletin <span class="bull_liensemestre"><a href="{
@ -1082,7 +1073,7 @@ def _formsemestre_bulletinetud_header_html(
<td>établi le {time.strftime("%d/%m/%Y à %Hh%M")} (notes sur 20)</td> <td>établi le {time.strftime("%d/%m/%Y à %Hh%M")} (notes sur 20)</td>
<td><span class="rightjust"> <td><span class="rightjust">
<input type="hidden" name="formsemestre_id" value="{formsemestre.id}"></input> <input type="hidden" name="formsemestre_id" value="{formsemestre.id}"></input>
<input type="hidden" name="etudid" value="{etudid}"></input> <input type="hidden" name="etudid" value="{etud.id}"></input>
<input type="hidden" name="format" value="{format}"></input> <input type="hidden" name="format" value="{format}"></input>
<select name="version" onchange="document.f.submit()" class="noprint"> <select name="version" onchange="document.f.submit()" class="noprint">
""", """,
@ -1100,8 +1091,52 @@ def _formsemestre_bulletinetud_header_html(
H.append("""</select></td>""") H.append("""</select></td>""")
# Menu # Menu
endpoint = "notes.formsemestre_bulletinetud" endpoint = "notes.formsemestre_bulletinetud"
menu_autres_operations = make_menu_autres_operations(
formsemestre, etud, endpoint, version
)
menuBul = [ H.append("""<td class="bulletin_menubar"><div class="bulletin_menubar">""")
H.append(menu_autres_operations)
H.append("""</div></td>""")
H.append(
'<td> <a href="%s">%s</a></td>'
% (
url_for(
"notes.formsemestre_bulletinetud",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id,
etudid=etud.id,
format="pdf",
version=version,
),
scu.ICON_PDF,
)
)
H.append("""</tr></table>""")
#
H.append(
"""</form></span></td><td class="bull_photo"><a href="%s">%s</a>
"""
% (
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id),
sco_photos.etud_photo_html(etud, title="fiche de " + etud.nomprenom),
)
)
H.append(
"""</td></tr>
</table>
"""
)
return "".join(H)
def make_menu_autres_operations(
formsemestre: FormSemestre, etud: Identite, endpoint: str, version: str
) -> str:
etud_email = etud.get_first_email() or ""
etud_perso = etud.get_first_email("emailperso") or ""
menu_items = [
{ {
"title": "Réglages bulletins", "title": "Réglages bulletins",
"endpoint": "notes.formsemestre_edit_options", "endpoint": "notes.formsemestre_edit_options",
@ -1124,43 +1159,42 @@ def _formsemestre_bulletinetud_header_html(
"endpoint": endpoint, "endpoint": endpoint,
"args": { "args": {
"formsemestre_id": formsemestre.id, "formsemestre_id": formsemestre.id,
"etudid": etudid, "etudid": etud.id,
"version": version, "version": version,
"format": "pdf", "format": "pdf",
}, },
}, },
{ {
"title": "Envoi par mail à %s" % etud["email"], "title": f"Envoi par mail à {etud_email}",
"endpoint": endpoint, "endpoint": endpoint,
"args": { "args": {
"formsemestre_id": formsemestre.id, "formsemestre_id": formsemestre.id,
"etudid": etudid, "etudid": etud.id,
"version": version, "version": version,
"format": "pdfmail", "format": "pdfmail",
}, },
# possible slt si on a un mail... # 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"], "title": f"Envoi par mail à {etud_perso} (adr. personnelle)",
"endpoint": endpoint, "endpoint": endpoint,
"args": { "args": {
"formsemestre_id": formsemestre.id, "formsemestre_id": formsemestre.id,
"etudid": etudid, "etudid": etud.id,
"version": version, "version": version,
"format": "pdfmail", "format": "pdfmail",
"prefer_mail_perso": 1, "prefer_mail_perso": 1,
}, },
# possible slt si on a un mail... # possible slt si on a un mail...
"enabled": etud["emailperso"] "enabled": etud_perso and can_send_bulletin_by_mail(formsemestre.id),
and can_send_bulletin_by_mail(formsemestre.id),
}, },
{ {
"title": "Version json", "title": "Version json",
"endpoint": endpoint, "endpoint": endpoint,
"args": { "args": {
"formsemestre_id": formsemestre.id, "formsemestre_id": formsemestre.id,
"etudid": etudid, "etudid": etud.id,
"version": version, "version": version,
"format": "json", "format": "json",
}, },
@ -1170,7 +1204,7 @@ def _formsemestre_bulletinetud_header_html(
"endpoint": endpoint, "endpoint": endpoint,
"args": { "args": {
"formsemestre_id": formsemestre.id, "formsemestre_id": formsemestre.id,
"etudid": etudid, "etudid": etud.id,
"version": version, "version": version,
"format": "xml", "format": "xml",
}, },
@ -1180,7 +1214,7 @@ def _formsemestre_bulletinetud_header_html(
"endpoint": "notes.appreciation_add_form", "endpoint": "notes.appreciation_add_form",
"args": { "args": {
"formsemestre_id": formsemestre.id, "formsemestre_id": formsemestre.id,
"etudid": etudid, "etudid": etud.id,
}, },
"enabled": ( "enabled": (
formsemestre.can_be_edited_by(current_user) formsemestre.can_be_edited_by(current_user)
@ -1192,7 +1226,7 @@ def _formsemestre_bulletinetud_header_html(
"endpoint": "notes.formsemestre_ext_create_form", "endpoint": "notes.formsemestre_ext_create_form",
"args": { "args": {
"formsemestre_id": formsemestre.id, "formsemestre_id": formsemestre.id,
"etudid": etudid, "etudid": etud.id,
}, },
"enabled": current_user.has_permission(Permission.ScoImplement), "enabled": current_user.has_permission(Permission.ScoImplement),
}, },
@ -1201,7 +1235,7 @@ def _formsemestre_bulletinetud_header_html(
"endpoint": "notes.formsemestre_validate_previous_ue", "endpoint": "notes.formsemestre_validate_previous_ue",
"args": { "args": {
"formsemestre_id": formsemestre.id, "formsemestre_id": formsemestre.id,
"etudid": etudid, "etudid": etud.id,
}, },
"enabled": sco_permissions_check.can_validate_sem(formsemestre.id), "enabled": sco_permissions_check.can_validate_sem(formsemestre.id),
}, },
@ -1210,7 +1244,7 @@ def _formsemestre_bulletinetud_header_html(
"endpoint": "notes.external_ue_create_form", "endpoint": "notes.external_ue_create_form",
"args": { "args": {
"formsemestre_id": formsemestre.id, "formsemestre_id": formsemestre.id,
"etudid": etudid, "etudid": etud.id,
}, },
"enabled": sco_permissions_check.can_validate_sem(formsemestre.id), "enabled": sco_permissions_check.can_validate_sem(formsemestre.id),
}, },
@ -1219,7 +1253,7 @@ def _formsemestre_bulletinetud_header_html(
"endpoint": "notes.formsemestre_validation_etud_form", "endpoint": "notes.formsemestre_validation_etud_form",
"args": { "args": {
"formsemestre_id": formsemestre.id, "formsemestre_id": formsemestre.id,
"etudid": etudid, "etudid": etud.id,
}, },
"enabled": sco_permissions_check.can_validate_sem(formsemestre.id), "enabled": sco_permissions_check.can_validate_sem(formsemestre.id),
}, },
@ -1228,43 +1262,44 @@ def _formsemestre_bulletinetud_header_html(
"endpoint": "notes.formsemestre_pvjury_pdf", "endpoint": "notes.formsemestre_pvjury_pdf",
"args": { "args": {
"formsemestre_id": formsemestre.id, "formsemestre_id": formsemestre.id,
"etudid": etudid, "etudid": etud.id,
}, },
"enabled": True, "enabled": True,
}, },
] ]
return htmlutils.make_menu("Autres opérations", menu_items, alone=True)
H.append("""<td class="bulletin_menubar"><div class="bulletin_menubar">""")
H.append(htmlutils.make_menu("Autres opérations", menuBul, alone=True)) def _formsemestre_bulletinetud_header_html(
H.append("""</div></td>""") etud,
H.append( formsemestre: FormSemestre,
'<td> <a href="%s">%s</a></td>' format=None,
% ( version=None,
url_for( ):
"notes.formsemestre_bulletinetud", H = [
scodoc_dept=g.scodoc_dept, html_sco_header.sco_header(
formsemestre_id=formsemestre.id, page_title=f"Bulletin de {etud.nomprenom}",
etudid=etudid, javascripts=[
format="pdf", "js/bulletin.js",
"libjs/d3.v3.min.js",
"js/radar_bulletin.js",
],
cssstyles=["css/radar_bulletin.css"],
),
render_template(
"bul_head.html",
etud=etud,
format=format,
formsemestre=formsemestre,
menu_autres_operations=make_menu_autres_operations(
etud=etud,
formsemestre=formsemestre,
endpoint="notes.formsemestre_bulletinetud",
version=version, version=version,
), ),
scu.ICON_PDF, scu=scu,
) time=time,
) version=version,
H.append("""</tr></table>""") ),
# ]
H.append( return "\n".join(H)
"""</form></span></td><td class="bull_photo"><a href="%s">%s</a>
"""
% (
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid),
sco_photos.etud_photo_html(etud, title="fiche de " + etud["nom"]),
)
)
H.append(
"""</td></tr>
</table>
"""
)
return "".join(H)

View File

@ -117,7 +117,7 @@ class BulletinGenerator:
def get_filename(self): def get_filename(self):
"""Build a filename to be proposed to the web client""" """Build a filename to be proposed to the web client"""
sem = sco_formsemestre.get_formsemestre(self.infos["formsemestre_id"]) sem = sco_formsemestre.get_formsemestre(self.infos["formsemestre_id"])
return scu.bul_filename(sem, self.infos["etud"], "pdf") return scu.bul_filename_old(sem, self.infos["etud"], "pdf")
def generate(self, format="", stand_alone=True): def generate(self, format="", stand_alone=True):
"""Return bulletin in specified format""" """Return bulletin in specified format"""

View File

@ -138,7 +138,7 @@ def formsemestre_bulletinetud_published_dict(
if not published: if not published:
return d # stop ! return d # stop !
etat_inscription = etud.etat_inscription(formsemestre.id) etat_inscription = etud.inscription_etat(formsemestre.id)
if etat_inscription != scu.INSCRIT: if etat_inscription != scu.INSCRIT:
d.update(dict_decision_jury(etudid, formsemestre_id, with_decisions=True)) d.update(dict_decision_jury(etudid, formsemestre_id, with_decisions=True))
return d return d

View File

@ -33,8 +33,7 @@ import os
import time import time
from operator import itemgetter from operator import itemgetter
from flask import url_for, g, request from flask import url_for, g
from flask_mail import Message
from app import email from app import email
from app import log from app import log
@ -46,7 +45,6 @@ from app.scodoc.sco_exceptions import ScoGenError, ScoValueError
from app.scodoc import safehtml from app.scodoc import safehtml
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app.scodoc.scolog import logdb from app.scodoc.scolog import logdb
from app.scodoc.TrivialFormulator import TrivialFormulator
def format_etud_ident(etud): def format_etud_ident(etud):
@ -860,7 +858,7 @@ def list_scolog(etudid):
return cursor.dictfetchall() return cursor.dictfetchall()
def fill_etuds_info(etuds, add_admission=True): def fill_etuds_info(etuds: list[dict], add_admission=True):
"""etuds est une liste d'etudiants (mappings) """etuds est une liste d'etudiants (mappings)
Pour chaque etudiant, ajoute ou formatte les champs Pour chaque etudiant, ajoute ou formatte les champs
-> informations pour fiche etudiant ou listes diverses -> informations pour fiche etudiant ou listes diverses
@ -977,7 +975,10 @@ def etud_inscriptions_infos(etudid: int, ne="") -> dict:
def descr_situation_etud(etudid: int, ne="") -> str: def descr_situation_etud(etudid: int, ne="") -> str:
"""chaîne décrivant la situation actuelle de l'étudiant""" """Chaîne décrivant la situation actuelle de l'étudiant
XXX Obsolete, utiliser Identite.descr_situation_etud() dans
les nouveaux codes
"""
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()

View File

@ -351,6 +351,7 @@ def copy_portal_photo_to_fs(etud):
"""Copy the photo from portal (distant website) to local fs. """Copy the photo from portal (distant website) to local fs.
Returns rel. path or None if copy failed, with a diagnostic message Returns rel. path or None if copy failed, with a diagnostic message
""" """
if "nomprenom" not in etud:
sco_etud.format_etud_ident(etud) sco_etud.format_etud_ident(etud)
url = photo_portal_url(etud) url = photo_portal_url(etud)
if not url: if not url:

View File

@ -608,7 +608,7 @@ def is_valid_filename(filename):
return VALID_EXP.match(filename) return VALID_EXP.match(filename)
def bul_filename(sem, etud, format): def bul_filename_old(sem: dict, etud: dict, format):
"""Build a filename for this bulletin""" """Build a filename for this bulletin"""
dt = time.strftime("%Y-%m-%d") dt = time.strftime("%Y-%m-%d")
filename = f"bul-{sem['titre_num']}-{dt}-{etud['nom']}.{format}" filename = f"bul-{sem['titre_num']}-{dt}-{etud['nom']}.{format}"
@ -616,6 +616,14 @@ def bul_filename(sem, etud, format):
return filename return filename
def bul_filename(formsemestre, etud, format):
"""Build a filename for this bulletin"""
dt = time.strftime("%Y-%m-%d")
filename = f"bul-{formsemestre.sem.titre_num}-{dt}-{etud.nom}.{format}"
filename = make_filename(filename)
return filename
def flash_errors(form): def flash_errors(form):
"""Flashes form errors (version sommaire)""" """Flashes form errors (version sommaire)"""
for field, errors in form.errors.items(): for field, errors in form.errors.items():

View File

@ -41,7 +41,7 @@ class releveBUT extends HTMLElement {
} }
set showData(data) { set showData(data) {
this.showInformations(data); // this.showInformations(data);
this.showSemestre(data); this.showSemestre(data);
this.showSynthese(data); this.showSynthese(data);
this.showEvaluations(data); this.showEvaluations(data);
@ -68,13 +68,7 @@ class releveBUT extends HTMLElement {
<div> <div>
<div class="wait"></div> <div class="wait"></div>
<main class="releve"> <main class="releve">
<!--------------------------->
<!-- Info. étudiant -->
<!--------------------------->
<section class=etudiant>
<img class=studentPic src="" alt="Photo de l'étudiant" width=100 height=120>
<div class=infoEtudiant></div>
</section>
<!---------------------------------------------------------------------------------------> <!--------------------------------------------------------------------------------------->
<!-- Zone spéciale pour que les IUT puisse ajouter des infos locales sur la passerelle --> <!-- Zone spéciale pour que les IUT puisse ajouter des infos locales sur la passerelle -->

View File

@ -0,0 +1,58 @@
{# -*- mode: jinja-html -*- #}
{# L'en-tête des bulletins HTML #}
{# was _formsemestre_bulletinetud_header_html #}
<table class="bull_head">
<tr>
<td>
<h2><a class="discretelink" href="{{
url_for(
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=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="{{etud.id}}"></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"),
("selectedevals", "Version intermédiaire"),
("long", "Version complète"),
) %}
<option value="{{v}}" {% if (v == version) %}selected{% endif %}>{{e}}</option>
{% endfor %}
</select>
</span>
</td>
<td class="bulletin_menubar">
<div class="bulletin_menubar">{{menu_autres_operations|safe}}</div>
</td>
<td><a href="{{url_for(
'notes.formsemestre_bulletinetud',
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id,
etudid=etud.id,
format='pdf',
version=version,
)}}">{{scu.ICON_PDF|safe}}</a>
</td>
</tr>
</table>
</form>
</td>
<td class="bull_photo"><a href="{{
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id)
}}">{{etud.photo_html(title="fiche de " + etud["nom"])|safe}}</a>
</td>
</tr>
</table>

View File

@ -6,6 +6,8 @@
{% endblock %} {% endblock %}
{% block app_content %} {% block app_content %}
<h2>Totoro</h2>
<releve-but></releve-but> <releve-but></releve-but>
<script src="/ScoDoc/static/js/releve-but.js"></script> <script src="/ScoDoc/static/js/releve-but.js"></script>