forked from ScoDoc/ScoDoc
refactoring et préparatifs pour lettres individuelles BUT
This commit is contained in:
parent
206825c42c
commit
543c3759d9
@ -21,6 +21,8 @@ from flask import g, url_for
|
|||||||
from app import db
|
from app import db
|
||||||
from app import log
|
from app import log
|
||||||
from app.comp.res_but import ResultatsSemestreBUT
|
from app.comp.res_but import ResultatsSemestreBUT
|
||||||
|
from app.comp.res_compat import NotesTableCompat
|
||||||
|
|
||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
from app.models import formsemestre
|
from app.models import formsemestre
|
||||||
|
|
||||||
@ -50,7 +52,16 @@ from app.scodoc.sco_exceptions import ScoException, ScoValueError
|
|||||||
from app.scodoc import sco_cursus_dut
|
from app.scodoc import sco_cursus_dut
|
||||||
|
|
||||||
|
|
||||||
class SituationEtudCursusBUT(sco_cursus_dut.SituationEtudCursus):
|
class SituationEtudCursusBUT(sco_cursus_dut.SituationEtudCursusClassic):
|
||||||
def __init__(self, etud: dict, formsemestre_id: int, res: ResultatsSemestreBUT):
|
def __init__(self, etud: dict, formsemestre_id: int, res: ResultatsSemestreBUT):
|
||||||
self.semestre_non_terminal = bool
|
super().__init__(etud, formsemestre_id, res)
|
||||||
self.formation
|
# Ajustements pour le BUT
|
||||||
|
self.can_compensate_with_prev = False # jamais de compensation à la mode DUT
|
||||||
|
|
||||||
|
def check_compensation_dut(self, semc: dict, ntc: NotesTableCompat):
|
||||||
|
"Jamais de compensation façon DUT"
|
||||||
|
return False
|
||||||
|
|
||||||
|
def parcours_validated(self):
|
||||||
|
"True si le parcours est validé"
|
||||||
|
return False # XXX TODO
|
||||||
|
@ -341,9 +341,7 @@ class SituationEtudCursusClassic(SituationEtudCursus):
|
|||||||
)[0]["formation_code"]
|
)[0]["formation_code"]
|
||||||
# si sem peut servir à compenser le semestre courant, positionne
|
# si sem peut servir à compenser le semestre courant, positionne
|
||||||
# can_compensate
|
# can_compensate
|
||||||
sem["can_compensate"] = check_compensation(
|
sem["can_compensate"] = self.check_compensation_dut(sem, nt)
|
||||||
self.etudid, self.sem, self.nt, sem, nt
|
|
||||||
)
|
|
||||||
|
|
||||||
self.ue_acros = list(ue_acros.keys())
|
self.ue_acros = list(ue_acros.keys())
|
||||||
self.ue_acros.sort()
|
self.ue_acros.sort()
|
||||||
@ -655,6 +653,46 @@ class SituationEtudCursusClassic(SituationEtudCursus):
|
|||||||
formsemestre_id=formsemestre_id
|
formsemestre_id=formsemestre_id
|
||||||
) # > modif decision jury
|
) # > modif decision jury
|
||||||
|
|
||||||
|
def check_compensation_dut(self, semc: dict, ntc: NotesTableCompat):
|
||||||
|
"""Compensations DUT
|
||||||
|
Vérifie si le semestre sem peut se compenser en utilisant semc
|
||||||
|
- semc non utilisé par un autre semestre
|
||||||
|
- decision du jury prise ADM ou ADJ ou ATT ou ADC
|
||||||
|
- barres UE (moy ue > 8) dans sem et semc
|
||||||
|
- moyenne des moy_gen > 10
|
||||||
|
Return boolean
|
||||||
|
"""
|
||||||
|
# -- deja utilise ?
|
||||||
|
decc = ntc.get_etud_decision_sem(self.etudid)
|
||||||
|
if (
|
||||||
|
decc
|
||||||
|
and decc["compense_formsemestre_id"]
|
||||||
|
and decc["compense_formsemestre_id"] != self.sem["formsemestre_id"]
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
# -- semestres consecutifs ?
|
||||||
|
if abs(self.sem["semestre_id"] - semc["semestre_id"]) != 1:
|
||||||
|
return False
|
||||||
|
# -- decision jury:
|
||||||
|
if decc and not decc["code"] in (ADM, ADJ, ATT, ADC):
|
||||||
|
return False
|
||||||
|
# -- barres UE et moyenne des moyennes:
|
||||||
|
moy_gen = self.nt.get_etud_moy_gen(self.etudid)
|
||||||
|
moy_genc = ntc.get_etud_moy_gen(self.etudid)
|
||||||
|
try:
|
||||||
|
moy_moy = (moy_gen + moy_genc) / 2
|
||||||
|
except: # un des semestres sans aucune note !
|
||||||
|
return False
|
||||||
|
|
||||||
|
if (
|
||||||
|
self.nt.etud_check_conditions_ues(self.etudid)[0]
|
||||||
|
and ntc.etud_check_conditions_ues(self.etudid)[0]
|
||||||
|
and moy_moy >= NOTES_BARRE_GEN_COMPENSATION
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class SituationEtudCursusECTS(SituationEtudCursusClassic):
|
class SituationEtudCursusECTS(SituationEtudCursusClassic):
|
||||||
"""Gestion parcours basés sur ECTS"""
|
"""Gestion parcours basés sur ECTS"""
|
||||||
@ -701,47 +739,6 @@ class SituationEtudCursusECTS(SituationEtudCursusClassic):
|
|||||||
return choices
|
return choices
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
def check_compensation(etudid, sem, nt, semc, ntc):
|
|
||||||
"""Verifie si le semestre sem peut se compenser en utilisant semc
|
|
||||||
- semc non utilisé par un autre semestre
|
|
||||||
- decision du jury prise ADM ou ADJ ou ATT ou ADC
|
|
||||||
- barres UE (moy ue > 8) dans sem et semc
|
|
||||||
- moyenne des moy_gen > 10
|
|
||||||
Return boolean
|
|
||||||
"""
|
|
||||||
# -- deja utilise ?
|
|
||||||
decc = ntc.get_etud_decision_sem(etudid)
|
|
||||||
if (
|
|
||||||
decc
|
|
||||||
and decc["compense_formsemestre_id"]
|
|
||||||
and decc["compense_formsemestre_id"] != sem["formsemestre_id"]
|
|
||||||
):
|
|
||||||
return False
|
|
||||||
# -- semestres consecutifs ?
|
|
||||||
if abs(sem["semestre_id"] - semc["semestre_id"]) != 1:
|
|
||||||
return False
|
|
||||||
# -- decision jury:
|
|
||||||
if decc and not decc["code"] in (ADM, ADJ, ATT, ADC):
|
|
||||||
return False
|
|
||||||
# -- barres UE et moyenne des moyennes:
|
|
||||||
moy_gen = nt.get_etud_moy_gen(etudid)
|
|
||||||
moy_genc = ntc.get_etud_moy_gen(etudid)
|
|
||||||
try:
|
|
||||||
moy_moy = (moy_gen + moy_genc) / 2
|
|
||||||
except: # un des semestres sans aucune note !
|
|
||||||
return False
|
|
||||||
|
|
||||||
if (
|
|
||||||
nt.etud_check_conditions_ues(etudid)[0]
|
|
||||||
and ntc.etud_check_conditions_ues(etudid)[0]
|
|
||||||
and moy_moy >= NOTES_BARRE_GEN_COMPENSATION
|
|
||||||
):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------------------------
|
# -------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ def get_formsemestre(formsemestre_id, raise_soft_exc=False):
|
|||||||
return g.stored_get_formsemestre[formsemestre_id]
|
return g.stored_get_formsemestre[formsemestre_id]
|
||||||
if not isinstance(formsemestre_id, int):
|
if not isinstance(formsemestre_id, int):
|
||||||
log(f"get_formsemestre: invalid id '{formsemestre_id}'")
|
log(f"get_formsemestre: invalid id '{formsemestre_id}'")
|
||||||
raise ScoInvalidIdType("formsemestre_id must be an integer !")
|
raise ScoInvalidIdType("get_formsemestre: formsemestre_id must be an integer !")
|
||||||
sems = do_formsemestre_list(args={"formsemestre_id": formsemestre_id})
|
sems = do_formsemestre_list(args={"formsemestre_id": formsemestre_id})
|
||||||
if not sems:
|
if not sems:
|
||||||
log("get_formsemestre: invalid formsemestre_id (%s)" % formsemestre_id)
|
log("get_formsemestre: invalid formsemestre_id (%s)" % formsemestre_id)
|
||||||
|
@ -103,14 +103,14 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
moy[etud.id] = nt.get_etud_moy_gen(etud.id)
|
moy[etud.id] = nt.get_etud_moy_gen(etud.id)
|
||||||
for ue in nt.get_ues_stat_dict(filter_sport=True):
|
for ue in nt.get_ues_stat_dict(filter_sport=True):
|
||||||
ue_status = nt.get_etud_ue_status(etud.id, ue["ue_id"])
|
ue_status = nt.get_etud_ue_status(etud.id, ue["ue_id"])
|
||||||
ue_code_s = ue["ue_code"] + "_%s" % nt.sem["semestre_id"]
|
ue_code_s = f'{ue["ue_code"]}_{nt.sem["semestre_id"]}'
|
||||||
moy_ue[ue_code_s][etud.id] = ue_status["moy"] if ue_status else ""
|
moy_ue[ue_code_s][etud.id] = ue_status["moy"] if ue_status else ""
|
||||||
ue_acro[ue_code_s] = (ue["numero"], ue["acronyme"], ue["titre"])
|
ue_acro[ue_code_s] = (ue["numero"], ue["acronyme"], ue["titre"])
|
||||||
|
|
||||||
if Se.prev:
|
if Se.prev:
|
||||||
try:
|
try:
|
||||||
moy_inter[etud.id] = (moy[etud.id] + prev_moy[etud.id]) / 2.0
|
moy_inter[etud.id] = (moy[etud.id] + prev_moy[etud.id]) / 2.0
|
||||||
except:
|
except (KeyError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
decision = nt.get_etud_decision_sem(etud.id)
|
decision = nt.get_etud_decision_sem(etud.id)
|
||||||
@ -120,10 +120,12 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
code[etud.id] += "+" # indique qu'il a servi a compenser
|
code[etud.id] += "+" # indique qu'il a servi a compenser
|
||||||
assidu[etud.id] = {False: "Non", True: "Oui"}.get(decision["assidu"], "")
|
assidu[etud.id] = {False: "Non", True: "Oui"}.get(decision["assidu"], "")
|
||||||
|
|
||||||
autorisations = ScolarAutorisationInscription.query.filter_by(
|
autorisations_etud = ScolarAutorisationInscription.query.filter_by(
|
||||||
etudid=etud.id, origin_formsemestre_id=formsemestre_id
|
etudid=etud.id, origin_formsemestre_id=formsemestre_id
|
||||||
).all()
|
).all()
|
||||||
autorisations[etud.id] = ", ".join(["S{x.semestre_id}" for x in autorisations])
|
autorisations[etud.id] = ", ".join(
|
||||||
|
[f"S{x.semestre_id}" for x in autorisations_etud]
|
||||||
|
)
|
||||||
# parcours:
|
# parcours:
|
||||||
parcours[etud.id] = Se.get_parcours_descr()
|
parcours[etud.id] = Se.get_parcours_descr()
|
||||||
# groupe principal (td)
|
# groupe principal (td)
|
||||||
@ -154,11 +156,11 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
sid = sem["semestre_id"]
|
sid = sem["semestre_id"]
|
||||||
sn = sp = ""
|
sn = sp = ""
|
||||||
if sid >= 0:
|
if sid >= 0:
|
||||||
sn = "S%s" % sid
|
sn = f"S{sid}"
|
||||||
if prev_moy: # si qq chose dans precedent
|
if prev_moy: # si qq chose dans precedent
|
||||||
sp = "S%s" % (sid - 1)
|
sp = f"S{sid - 1}"
|
||||||
|
|
||||||
ws = sco_excel.ScoExcelSheet(sheet_name="Prepa Jury %s" % sn)
|
sheet = sco_excel.ScoExcelSheet(sheet_name=f"Prepa Jury {sn}")
|
||||||
# génération des styles
|
# génération des styles
|
||||||
style_bold = sco_excel.excel_make_style(size=10, bold=True)
|
style_bold = sco_excel.excel_make_style(size=10, bold=True)
|
||||||
style_center = sco_excel.excel_make_style(halign="center")
|
style_center = sco_excel.excel_make_style(halign="center")
|
||||||
@ -174,10 +176,10 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Première ligne
|
# Première ligne
|
||||||
ws.append_single_cell_row(
|
sheet.append_single_cell_row(
|
||||||
"Feuille préparation Jury %s" % scu.unescape_html(sem["titreannee"]), style_bold
|
"Feuille préparation Jury %s" % scu.unescape_html(sem["titreannee"]), style_bold
|
||||||
)
|
)
|
||||||
ws.append_blank_row()
|
sheet.append_blank_row()
|
||||||
|
|
||||||
# Ligne de titre
|
# Ligne de titre
|
||||||
titles = ["Rang"]
|
titles = ["Rang"]
|
||||||
@ -199,25 +201,25 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
]
|
]
|
||||||
if prev_moy: # si qq chose dans precedent
|
if prev_moy: # si qq chose dans precedent
|
||||||
titles += [prev_ue_acro[x][1] for x in ue_prev_codes] + [
|
titles += [prev_ue_acro[x][1] for x in ue_prev_codes] + [
|
||||||
"Moy %s" % sp,
|
f"Moy {sp}",
|
||||||
"Décision %s" % sp,
|
f"Décision {sp}",
|
||||||
]
|
]
|
||||||
titles += [ue_acro[x][1] for x in ue_codes] + ["Moy %s" % sn]
|
titles += [ue_acro[x][1] for x in ue_codes] + [f"Moy {sn}"]
|
||||||
if moy_inter:
|
if moy_inter:
|
||||||
titles += ["Moy %s-%s" % (sp, sn)]
|
titles += [f"Moy {sp}-{sn}"]
|
||||||
titles += ["Abs", "Abs Injust."]
|
titles += ["Abs", "Abs Injust."]
|
||||||
if code:
|
if code:
|
||||||
titles.append("Proposit. %s" % sn)
|
titles.append("Proposit. {sn}")
|
||||||
if autorisations:
|
if autorisations:
|
||||||
titles.append("Autorisations")
|
titles.append("Autorisations")
|
||||||
# titles.append('Assidu')
|
# titles.append('Assidu')
|
||||||
ws.append_row(ws.make_row(titles, style_boldcenter))
|
sheet.append_row(sheet.make_row(titles, style_boldcenter))
|
||||||
if prev_moy:
|
# if prev_moy:
|
||||||
tit_prev_moy = "Moy " + sp
|
# tit_prev_moy = "Moy " + sp
|
||||||
col_prev_moy = titles.index(tit_prev_moy)
|
# # col_prev_moy = titles.index(tit_prev_moy)
|
||||||
tit_moy = "Moy " + sn
|
# tit_moy = "Moy " + sn
|
||||||
col_moy = titles.index(tit_moy)
|
# col_moy = titles.index(tit_moy)
|
||||||
col_abs = titles.index("Abs")
|
# col_abs = titles.index("Abs")
|
||||||
|
|
||||||
def fmt(x):
|
def fmt(x):
|
||||||
"reduit les notes a deux chiffres"
|
"reduit les notes a deux chiffres"
|
||||||
@ -230,13 +232,13 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
i = 1 # numero etudiant
|
i = 1 # numero etudiant
|
||||||
for etud in etuds:
|
for etud in etuds:
|
||||||
cells = []
|
cells = []
|
||||||
cells.append(ws.make_cell(str(i)))
|
cells.append(sheet.make_cell(str(i)))
|
||||||
if sco_preferences.get_preference("prepa_jury_nip"):
|
if sco_preferences.get_preference("prepa_jury_nip"):
|
||||||
cells.append(ws.make_cell(etud.code_nip))
|
cells.append(sheet.make_cell(etud.code_nip))
|
||||||
if sco_preferences.get_preference("prepa_jury_ine"):
|
if sco_preferences.get_preference("prepa_jury_ine"):
|
||||||
cells.append(ws.make_cell(etud.code_ine))
|
cells.append(sheet.make_cell(etud.code_ine))
|
||||||
admission = etud.admission.first()
|
admission = etud.admission.first()
|
||||||
cells += ws.make_row(
|
cells += sheet.make_row(
|
||||||
[
|
[
|
||||||
etud.id,
|
etud.id,
|
||||||
etud.civilite_str,
|
etud.civilite_str,
|
||||||
@ -254,50 +256,52 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
if prev_moy:
|
if prev_moy:
|
||||||
for ue_acro in ue_prev_codes:
|
for ue_acro in ue_prev_codes:
|
||||||
cells.append(
|
cells.append(
|
||||||
ws.make_cell(
|
sheet.make_cell(
|
||||||
fmt(prev_moy_ue.get(ue_acro, {}).get(etud.id, "")), style_note
|
fmt(prev_moy_ue.get(ue_acro, {}).get(etud.id, "")), style_note
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
co += 1
|
co += 1
|
||||||
cells.append(
|
cells.append(
|
||||||
ws.make_cell(fmt(prev_moy.get(etud.id, "")), style_bold)
|
sheet.make_cell(fmt(prev_moy.get(etud.id, "")), style_bold)
|
||||||
) # moy gen prev
|
) # moy gen prev
|
||||||
cells.append(
|
cells.append(
|
||||||
ws.make_cell(fmt(prev_code.get(etud.id, "")), style_moy)
|
sheet.make_cell(fmt(prev_code.get(etud.id, "")), style_moy)
|
||||||
) # decision prev
|
) # decision prev
|
||||||
co += 2
|
co += 2
|
||||||
|
|
||||||
for ue_acro in ue_codes:
|
for ue_acro in ue_codes:
|
||||||
cells.append(
|
cells.append(
|
||||||
ws.make_cell(fmt(moy_ue.get(ue_acro, {}).get(etud.id, "")), style_note)
|
sheet.make_cell(
|
||||||
|
fmt(moy_ue.get(ue_acro, {}).get(etud.id, "")), style_note
|
||||||
|
)
|
||||||
)
|
)
|
||||||
co += 1
|
co += 1
|
||||||
cells.append(
|
cells.append(
|
||||||
ws.make_cell(fmt(moy.get(etud.id, "")), style_note_bold)
|
sheet.make_cell(fmt(moy.get(etud.id, "")), style_note_bold)
|
||||||
) # moy gen
|
) # moy gen
|
||||||
co += 1
|
co += 1
|
||||||
if moy_inter:
|
if moy_inter:
|
||||||
cells.append(ws.make_cell(fmt(moy_inter.get(etud.id, "")), style_note))
|
cells.append(sheet.make_cell(fmt(moy_inter.get(etud.id, "")), style_note))
|
||||||
cells.append(ws.make_cell(str(nbabs.get(etud.id, "")), style_center))
|
cells.append(sheet.make_cell(str(nbabs.get(etud.id, "")), style_center))
|
||||||
cells.append(ws.make_cell(str(nbabsjust.get(etud.id, "")), style_center))
|
cells.append(sheet.make_cell(str(nbabsjust.get(etud.id, "")), style_center))
|
||||||
if code:
|
if code:
|
||||||
cells.append(ws.make_cell(code.get(etud.id, ""), style_moy))
|
cells.append(sheet.make_cell(code.get(etud.id, ""), style_moy))
|
||||||
cells.append(ws.make_cell(autorisations.get(etud.id, ""), style_moy))
|
cells.append(sheet.make_cell(autorisations.get(etud.id, ""), style_moy))
|
||||||
# l.append(assidu.get(etud.id, ''))
|
# l.append(assidu.get(etud.id, ''))
|
||||||
ws.append_row(cells)
|
sheet.append_row(cells)
|
||||||
i += 1
|
i += 1
|
||||||
#
|
#
|
||||||
ws.append_blank_row()
|
sheet.append_blank_row()
|
||||||
# Explications des codes
|
# Explications des codes
|
||||||
codes = list(sco_codes_parcours.CODES_EXPL.keys())
|
codes = list(sco_codes_parcours.CODES_EXPL.keys())
|
||||||
codes.sort()
|
codes.sort()
|
||||||
ws.append_single_cell_row("Explication des codes")
|
sheet.append_single_cell_row("Explication des codes")
|
||||||
for code in codes:
|
for code in codes:
|
||||||
ws.append_row(
|
sheet.append_row(
|
||||||
ws.make_row(["", "", "", code, sco_codes_parcours.CODES_EXPL[code]])
|
sheet.make_row(["", "", "", code, sco_codes_parcours.CODES_EXPL[code]])
|
||||||
)
|
)
|
||||||
ws.append_row(
|
sheet.append_row(
|
||||||
ws.make_row(
|
sheet.make_row(
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
@ -308,16 +312,16 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
# UE : Correspondances acronyme et titre complet
|
# UE : Correspondances acronyme et titre complet
|
||||||
ws.append_blank_row()
|
sheet.append_blank_row()
|
||||||
ws.append_single_cell_row("Titre des UE")
|
sheet.append_single_cell_row("Titre des UE")
|
||||||
if prev_moy:
|
if prev_moy:
|
||||||
for ue in ntp.get_ues_stat_dict(filter_sport=True):
|
for ue in ntp.get_ues_stat_dict(filter_sport=True):
|
||||||
ws.append_row(ws.make_row(["", "", "", ue["acronyme"], ue["titre"]]))
|
sheet.append_row(sheet.make_row(["", "", "", ue["acronyme"], ue["titre"]]))
|
||||||
for ue in nt.get_ues_stat_dict(filter_sport=True):
|
for ue in nt.get_ues_stat_dict(filter_sport=True):
|
||||||
ws.append_row(ws.make_row(["", "", "", ue["acronyme"], ue["titre"]]))
|
sheet.append_row(sheet.make_row(["", "", "", ue["acronyme"], ue["titre"]]))
|
||||||
#
|
#
|
||||||
ws.append_blank_row()
|
sheet.append_blank_row()
|
||||||
ws.append_single_cell_row(
|
sheet.append_single_cell_row(
|
||||||
"Préparé par %s le %s sur %s pour %s"
|
"Préparé par %s le %s sur %s pour %s"
|
||||||
% (
|
% (
|
||||||
sco_version.SCONAME,
|
sco_version.SCONAME,
|
||||||
@ -326,7 +330,7 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
current_user,
|
current_user,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
xls = ws.generate()
|
xls = sheet.generate()
|
||||||
flash("Feuille préparation jury générée")
|
flash("Feuille préparation jury générée")
|
||||||
return scu.send_file(
|
return scu.send_file(
|
||||||
xls,
|
xls,
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
import io
|
import io
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from PIL import Image as PILImage
|
||||||
|
|
||||||
import reportlab
|
import reportlab
|
||||||
from reportlab.lib.units import cm, mm
|
from reportlab.lib.units import cm, mm
|
||||||
from reportlab.lib.enums import TA_RIGHT, TA_JUSTIFY
|
from reportlab.lib.enums import TA_RIGHT, TA_JUSTIFY
|
||||||
@ -41,6 +43,7 @@ from reportlab.lib import styles
|
|||||||
from reportlab.lib.colors import Color
|
from reportlab.lib.colors import Color
|
||||||
|
|
||||||
from flask import g
|
from flask import g
|
||||||
|
from app.models.formsemestre import FormSemestre
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc import sco_bulletins_pdf
|
from app.scodoc import sco_bulletins_pdf
|
||||||
@ -125,6 +128,7 @@ def page_footer(canvas, doc, logo, preferences, with_page_numbers=True):
|
|||||||
|
|
||||||
|
|
||||||
def page_header(canvas, doc, logo, preferences, only_on_first_page=False):
|
def page_header(canvas, doc, logo, preferences, only_on_first_page=False):
|
||||||
|
"Ajoute au canvas le frame avec le logo"
|
||||||
if only_on_first_page and int(doc.page) > 1:
|
if only_on_first_page and int(doc.page) > 1:
|
||||||
return
|
return
|
||||||
height = doc.pagesize[1]
|
height = doc.pagesize[1]
|
||||||
@ -147,12 +151,12 @@ def page_header(canvas, doc, logo, preferences, only_on_first_page=False):
|
|||||||
|
|
||||||
|
|
||||||
class CourrierIndividuelTemplate(PageTemplate):
|
class CourrierIndividuelTemplate(PageTemplate):
|
||||||
"""Template pour courrier avisant des decisions de jury (1 page /etudiant)"""
|
"""Template pour courrier avisant des decisions de jury (1 page par étudiant)"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
document,
|
document,
|
||||||
pagesbookmarks={},
|
pagesbookmarks=None,
|
||||||
author=None,
|
author=None,
|
||||||
title=None,
|
title=None,
|
||||||
subject=None,
|
subject=None,
|
||||||
@ -163,7 +167,7 @@ class CourrierIndividuelTemplate(PageTemplate):
|
|||||||
template_name="CourrierJuryTemplate",
|
template_name="CourrierJuryTemplate",
|
||||||
):
|
):
|
||||||
"""Initialise our page template."""
|
"""Initialise our page template."""
|
||||||
self.pagesbookmarks = pagesbookmarks
|
self.pagesbookmarks = pagesbookmarks or {}
|
||||||
self.pdfmeta_author = author
|
self.pdfmeta_author = author
|
||||||
self.pdfmeta_title = title
|
self.pdfmeta_title = title
|
||||||
self.pdfmeta_subject = subject
|
self.pdfmeta_subject = subject
|
||||||
@ -237,32 +241,32 @@ class CourrierIndividuelTemplate(PageTemplate):
|
|||||||
width=LOGO_HEADER_WIDTH,
|
width=LOGO_HEADER_WIDTH,
|
||||||
)
|
)
|
||||||
|
|
||||||
def beforeDrawPage(self, canvas, doc):
|
def beforeDrawPage(self, canv, doc):
|
||||||
"""Draws a logo and an contribution message on each page."""
|
"""Draws a logo and an contribution message on each page."""
|
||||||
# ---- Add some meta data and bookmarks
|
# ---- Add some meta data and bookmarks
|
||||||
if self.pdfmeta_author:
|
if self.pdfmeta_author:
|
||||||
canvas.setAuthor(SU(self.pdfmeta_author))
|
canv.setAuthor(SU(self.pdfmeta_author))
|
||||||
if self.pdfmeta_title:
|
if self.pdfmeta_title:
|
||||||
canvas.setTitle(SU(self.pdfmeta_title))
|
canv.setTitle(SU(self.pdfmeta_title))
|
||||||
if self.pdfmeta_subject:
|
if self.pdfmeta_subject:
|
||||||
canvas.setSubject(SU(self.pdfmeta_subject))
|
canv.setSubject(SU(self.pdfmeta_subject))
|
||||||
bm = self.pagesbookmarks.get(doc.page, None)
|
bm = self.pagesbookmarks.get(doc.page, None)
|
||||||
if bm != None:
|
if bm != None:
|
||||||
key = bm
|
key = bm
|
||||||
txt = SU(bm)
|
txt = SU(bm)
|
||||||
canvas.bookmarkPage(key)
|
canv.bookmarkPage(key)
|
||||||
canvas.addOutlineEntry(txt, bm)
|
canv.addOutlineEntry(txt, bm)
|
||||||
|
|
||||||
# ---- Background image
|
# ---- Background image
|
||||||
if self.background_image_filename and self.with_page_background:
|
if self.background_image_filename and self.with_page_background:
|
||||||
canvas.drawImage(
|
canv.drawImage(
|
||||||
self.background_image_filename, 0, 0, doc.pagesize[0], doc.pagesize[1]
|
self.background_image_filename, 0, 0, doc.pagesize[0], doc.pagesize[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
# ---- Header/Footer
|
# ---- Header/Footer
|
||||||
if self.with_header:
|
if self.with_header:
|
||||||
page_header(
|
page_header(
|
||||||
canvas,
|
canv,
|
||||||
doc,
|
doc,
|
||||||
self.logo_header,
|
self.logo_header,
|
||||||
self.preferences,
|
self.preferences,
|
||||||
@ -270,7 +274,7 @@ class CourrierIndividuelTemplate(PageTemplate):
|
|||||||
)
|
)
|
||||||
if self.with_footer:
|
if self.with_footer:
|
||||||
page_footer(
|
page_footer(
|
||||||
canvas,
|
canv,
|
||||||
doc,
|
doc,
|
||||||
self.logo_footer,
|
self.logo_footer,
|
||||||
self.preferences,
|
self.preferences,
|
||||||
@ -332,6 +336,39 @@ class PVTemplate(CourrierIndividuelTemplate):
|
|||||||
# self.__pageNum += 1
|
# self.__pageNum += 1
|
||||||
|
|
||||||
|
|
||||||
|
def _simulate_br(paragraph_txt: str, para="<para>") -> str:
|
||||||
|
"""Reportlab bug turnaround (could be removed in a future version).
|
||||||
|
p is a string with Reportlab intra-paragraph XML tags.
|
||||||
|
Replaces <br/> (currently ignored by Reportlab) by </para><para>
|
||||||
|
"""
|
||||||
|
return ("</para>" + para).join(re.split(r"<.*?br.*?/>", paragraph_txt))
|
||||||
|
|
||||||
|
|
||||||
|
def _make_signature_image(signature, leftindent, formsemestre_id) -> Table:
|
||||||
|
"crée un paragraphe avec l'image signature"
|
||||||
|
# cree une image PIL pour avoir la taille (W,H)
|
||||||
|
|
||||||
|
f = io.BytesIO(signature)
|
||||||
|
img = PILImage.open(f)
|
||||||
|
width, height = img.size
|
||||||
|
pdfheight = (
|
||||||
|
1.0
|
||||||
|
* sco_preferences.get_preference("pv_sig_image_height", formsemestre_id)
|
||||||
|
* mm
|
||||||
|
)
|
||||||
|
f.seek(0, 0)
|
||||||
|
|
||||||
|
style = styles.ParagraphStyle({})
|
||||||
|
style.leading = 1.0 * sco_preferences.get_preference(
|
||||||
|
"SCOLAR_FONT_SIZE", formsemestre_id
|
||||||
|
) # vertical space
|
||||||
|
style.leftIndent = leftindent
|
||||||
|
return Table(
|
||||||
|
[("", Image(f, width=width * pdfheight / float(height), height=pdfheight))],
|
||||||
|
colWidths=(9 * cm, 7 * cm),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def pdf_lettres_individuelles(
|
def pdf_lettres_individuelles(
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
etudids=None,
|
etudids=None,
|
||||||
@ -394,8 +431,8 @@ def pdf_lettres_individuelles(
|
|||||||
document.addPageTemplates(
|
document.addPageTemplates(
|
||||||
CourrierIndividuelTemplate(
|
CourrierIndividuelTemplate(
|
||||||
document,
|
document,
|
||||||
author="%s %s (E. Viennet)" % (sco_version.SCONAME, sco_version.SCOVERSION),
|
author=f"{sco_version.SCONAME} {sco_version.SCOVERSION} (E. Viennet)",
|
||||||
title="Lettres décision %s" % sem["titreannee"],
|
title=f"Lettres décision {sem['titreannee']}",
|
||||||
subject="Décision jury",
|
subject="Décision jury",
|
||||||
margins=margins,
|
margins=margins,
|
||||||
pagesbookmarks=bookmarks,
|
pagesbookmarks=bookmarks,
|
||||||
@ -410,10 +447,7 @@ def pdf_lettres_individuelles(
|
|||||||
|
|
||||||
def _descr_jury(sem, diplome):
|
def _descr_jury(sem, diplome):
|
||||||
if not diplome:
|
if not diplome:
|
||||||
t = "passage de Semestre %d en Semestre %d" % (
|
t = f"""passage de Semestre {sem["semestre_id"]} en Semestre {sem["semestre_id"] + 1}"""
|
||||||
sem["semestre_id"],
|
|
||||||
sem["semestre_id"] + 1,
|
|
||||||
)
|
|
||||||
s = "passage de semestre"
|
s = "passage de semestre"
|
||||||
else:
|
else:
|
||||||
t = "délivrance du diplôme"
|
t = "délivrance du diplôme"
|
||||||
@ -428,6 +462,7 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None):
|
|||||||
"""
|
"""
|
||||||
#
|
#
|
||||||
formsemestre_id = sem["formsemestre_id"]
|
formsemestre_id = sem["formsemestre_id"]
|
||||||
|
formsemestre = FormSemestre.query.get(formsemestre_id)
|
||||||
Se: SituationEtudCursus = decision["Se"]
|
Se: SituationEtudCursus = decision["Se"]
|
||||||
t, s = _descr_jury(sem, Se.parcours_validated() or not Se.semestre_non_terminal)
|
t, s = _descr_jury(sem, Se.parcours_validated() or not Se.semestre_non_terminal)
|
||||||
objects = []
|
objects = []
|
||||||
@ -437,7 +472,7 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None):
|
|||||||
style.leading = 18
|
style.leading = 18
|
||||||
style.alignment = TA_JUSTIFY
|
style.alignment = TA_JUSTIFY
|
||||||
|
|
||||||
params["semestre_id"] = sem["semestre_id"]
|
params["semestre_id"] = formsemestre.semestre_id
|
||||||
params["decision_sem_descr"] = decision["decision_sem_descr"]
|
params["decision_sem_descr"] = decision["decision_sem_descr"]
|
||||||
params["type_jury"] = t # type de jury (passage ou delivrance)
|
params["type_jury"] = t # type de jury (passage ou delivrance)
|
||||||
params["type_jury_abbrv"] = s # idem, abbrégé
|
params["type_jury_abbrv"] = s # idem, abbrégé
|
||||||
@ -450,28 +485,25 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None):
|
|||||||
params["INSTITUTION_CITY"] = (
|
params["INSTITUTION_CITY"] = (
|
||||||
sco_preferences.get_preference("INSTITUTION_CITY", formsemestre_id) or ""
|
sco_preferences.get_preference("INSTITUTION_CITY", formsemestre_id) or ""
|
||||||
)
|
)
|
||||||
|
|
||||||
if decision["prev_decision_sem"]:
|
if decision["prev_decision_sem"]:
|
||||||
params["prev_semestre_id"] = decision["prev"]["semestre_id"]
|
params["prev_semestre_id"] = decision["prev"]["semestre_id"]
|
||||||
params["prev_code_descr"] = decision["prev_code_descr"]
|
|
||||||
|
params["prev_decision_sem_txt"] = ""
|
||||||
|
params["decision_orig"] = ""
|
||||||
|
|
||||||
|
if formsemestre.formation.is_apc():
|
||||||
|
# ajout champs spécifiques PV BUT
|
||||||
|
add_apc_infos(formsemestre, params, decision)
|
||||||
|
else:
|
||||||
|
# ajout champs spécifiques PV DUT
|
||||||
|
add_classic_infos(formsemestre, params, decision)
|
||||||
|
|
||||||
params.update(decision["identite"])
|
params.update(decision["identite"])
|
||||||
# fix domicile
|
# fix domicile
|
||||||
if params["domicile"]:
|
if params["domicile"]:
|
||||||
params["domicile"] = params["domicile"].replace("\\n", "<br/>")
|
params["domicile"] = params["domicile"].replace("\\n", "<br/>")
|
||||||
|
|
||||||
# Décision semestre courant:
|
|
||||||
if sem["semestre_id"] >= 0:
|
|
||||||
params["decision_orig"] = "du semestre S%s" % sem["semestre_id"]
|
|
||||||
else:
|
|
||||||
params["decision_orig"] = ""
|
|
||||||
|
|
||||||
if decision["prev_decision_sem"]:
|
|
||||||
params["prev_decision_sem_txt"] = (
|
|
||||||
"""<b>Décision du semestre antérieur S%(prev_semestre_id)s :</b> %(prev_code_descr)s"""
|
|
||||||
% params
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
params["prev_decision_sem_txt"] = ""
|
|
||||||
# UE capitalisées:
|
# UE capitalisées:
|
||||||
if decision["decisions_ue"] and decision["decisions_ue_descr"]:
|
if decision["decisions_ue"] and decision["decisions_ue_descr"]:
|
||||||
params["decision_ue_txt"] = (
|
params["decision_ue_txt"] = (
|
||||||
@ -567,39 +599,23 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None):
|
|||||||
return objects
|
return objects
|
||||||
|
|
||||||
|
|
||||||
def _simulate_br(p, para="<para>"):
|
def add_classic_infos(formsemestre: FormSemestre, params: dict, decision: dict):
|
||||||
"""Reportlab bug turnaround (could be removed in a future version).
|
"""Ajoute les champs pour les formations classiques, donc avec codes semestres"""
|
||||||
p is a string with Reportlab intra-paragraph XML tags.
|
if decision["prev_decision_sem"]:
|
||||||
Replaces <br/> (currently ignored by Reportlab) by </para><para>
|
params["prev_code_descr"] = decision["prev_code_descr"]
|
||||||
"""
|
params[
|
||||||
l = re.split(r"<.*?br.*?/>", p)
|
"prev_decision_sem_txt"
|
||||||
return ("</para>" + para).join(l)
|
] = f"""<b>Décision du semestre antérieur S{params['prev_semestre_id']} :</b> {params['prev_code_descr']}"""
|
||||||
|
# Décision semestre courant:
|
||||||
|
if formsemestre.semestre_id >= 0:
|
||||||
|
params["decision_orig"] = f"du semestre S{formsemestre.semestre_id}"
|
||||||
|
else:
|
||||||
|
params["decision_orig"] = ""
|
||||||
|
|
||||||
|
|
||||||
def _make_signature_image(signature, leftindent, formsemestre_id):
|
def add_apc_infos(formsemestre: FormSemestre, params: dict, decision: dict):
|
||||||
"cree un paragraphe avec l'image signature"
|
"""Ajoute les champs pour les formations APC (BUT), donc avec codes RCUE et année"""
|
||||||
# cree une image PIL pour avoir la taille (W,H)
|
pass # TODO XXX
|
||||||
from PIL import Image as PILImage
|
|
||||||
|
|
||||||
f = io.BytesIO(signature)
|
|
||||||
im = PILImage.open(f)
|
|
||||||
width, height = im.size
|
|
||||||
pdfheight = (
|
|
||||||
1.0
|
|
||||||
* sco_preferences.get_preference("pv_sig_image_height", formsemestre_id)
|
|
||||||
* mm
|
|
||||||
)
|
|
||||||
f.seek(0, 0)
|
|
||||||
|
|
||||||
style = styles.ParagraphStyle({})
|
|
||||||
style.leading = 1.0 * sco_preferences.get_preference(
|
|
||||||
"SCOLAR_FONT_SIZE", formsemestre_id
|
|
||||||
) # vertical space
|
|
||||||
style.leftIndent = leftindent
|
|
||||||
return Table(
|
|
||||||
[("", Image(f, width=width * pdfheight / float(height), height=pdfheight))],
|
|
||||||
colWidths=(9 * cm, 7 * cm),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------
|
# ----------------------------------------------
|
||||||
|
@ -296,7 +296,9 @@ def formsemestre_bulletinetud(
|
|||||||
format = format or "html"
|
format = format or "html"
|
||||||
|
|
||||||
if not isinstance(formsemestre_id, int):
|
if not isinstance(formsemestre_id, int):
|
||||||
raise ScoInvalidIdType("formsemestre_id must be an integer !")
|
raise ScoInvalidIdType(
|
||||||
|
"formsemestre_bulletinetud: formsemestre_id must be an integer !"
|
||||||
|
)
|
||||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
if etudid:
|
if etudid:
|
||||||
etud = models.Identite.query.get_or_404(etudid)
|
etud = models.Identite.query.get_or_404(etudid)
|
||||||
@ -826,7 +828,9 @@ def XMLgetFormsemestres(etape_apo=None, formsemestre_id=None):
|
|||||||
if not formsemestre_id:
|
if not formsemestre_id:
|
||||||
return flask.abort(404, "argument manquant: formsemestre_id")
|
return flask.abort(404, "argument manquant: formsemestre_id")
|
||||||
if not isinstance(formsemestre_id, int):
|
if not isinstance(formsemestre_id, int):
|
||||||
return flask.abort(404, "formsemestre_id must be an integer !")
|
return flask.abort(
|
||||||
|
404, "XMLgetFormsemestres: formsemestre_id must be an integer !"
|
||||||
|
)
|
||||||
args = {}
|
args = {}
|
||||||
if etape_apo:
|
if etape_apo:
|
||||||
args["etape_apo"] = etape_apo
|
args["etape_apo"] = etape_apo
|
||||||
|
Loading…
Reference in New Issue
Block a user