refactoring et préparatifs pour lettres individuelles BUT

This commit is contained in:
Emmanuel Viennet 2022-07-07 23:34:14 +02:00
parent 206825c42c
commit 543c3759d9
6 changed files with 195 additions and 163 deletions

View File

@ -21,6 +21,8 @@ from flask import g, url_for
from app import db
from app import log
from app.comp.res_but import ResultatsSemestreBUT
from app.comp.res_compat import NotesTableCompat
from app.comp import res_sem
from app.models import formsemestre
@ -50,7 +52,16 @@ from app.scodoc.sco_exceptions import ScoException, ScoValueError
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):
self.semestre_non_terminal = bool
self.formation
super().__init__(etud, formsemestre_id, res)
# 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

View File

@ -341,9 +341,7 @@ class SituationEtudCursusClassic(SituationEtudCursus):
)[0]["formation_code"]
# si sem peut servir à compenser le semestre courant, positionne
# can_compensate
sem["can_compensate"] = check_compensation(
self.etudid, self.sem, self.nt, sem, nt
)
sem["can_compensate"] = self.check_compensation_dut(sem, nt)
self.ue_acros = list(ue_acros.keys())
self.ue_acros.sort()
@ -655,6 +653,46 @@ class SituationEtudCursusClassic(SituationEtudCursus):
formsemestre_id=formsemestre_id
) # > 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):
"""Gestion parcours basés sur ECTS"""
@ -701,47 +739,6 @@ class SituationEtudCursusECTS(SituationEtudCursusClassic):
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
# -------------------------------------------------------------------------------------------

View File

@ -101,7 +101,7 @@ def get_formsemestre(formsemestre_id, raise_soft_exc=False):
return g.stored_get_formsemestre[formsemestre_id]
if not isinstance(formsemestre_id, int):
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})
if not sems:
log("get_formsemestre: invalid formsemestre_id (%s)" % formsemestre_id)

View File

@ -103,14 +103,14 @@ def feuille_preparation_jury(formsemestre_id):
moy[etud.id] = nt.get_etud_moy_gen(etud.id)
for ue in nt.get_ues_stat_dict(filter_sport=True):
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 ""
ue_acro[ue_code_s] = (ue["numero"], ue["acronyme"], ue["titre"])
if Se.prev:
try:
moy_inter[etud.id] = (moy[etud.id] + prev_moy[etud.id]) / 2.0
except:
except (KeyError, TypeError):
pass
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
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
).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[etud.id] = Se.get_parcours_descr()
# groupe principal (td)
@ -154,11 +156,11 @@ def feuille_preparation_jury(formsemestre_id):
sid = sem["semestre_id"]
sn = sp = ""
if sid >= 0:
sn = "S%s" % sid
sn = f"S{sid}"
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
style_bold = sco_excel.excel_make_style(size=10, bold=True)
style_center = sco_excel.excel_make_style(halign="center")
@ -174,10 +176,10 @@ def feuille_preparation_jury(formsemestre_id):
)
# 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
)
ws.append_blank_row()
sheet.append_blank_row()
# Ligne de titre
titles = ["Rang"]
@ -199,25 +201,25 @@ def feuille_preparation_jury(formsemestre_id):
]
if prev_moy: # si qq chose dans precedent
titles += [prev_ue_acro[x][1] for x in ue_prev_codes] + [
"Moy %s" % sp,
"Décision %s" % sp,
f"Moy {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:
titles += ["Moy %s-%s" % (sp, sn)]
titles += [f"Moy {sp}-{sn}"]
titles += ["Abs", "Abs Injust."]
if code:
titles.append("Proposit. %s" % sn)
titles.append("Proposit. {sn}")
if autorisations:
titles.append("Autorisations")
# titles.append('Assidu')
ws.append_row(ws.make_row(titles, style_boldcenter))
if prev_moy:
tit_prev_moy = "Moy " + sp
col_prev_moy = titles.index(tit_prev_moy)
tit_moy = "Moy " + sn
col_moy = titles.index(tit_moy)
col_abs = titles.index("Abs")
sheet.append_row(sheet.make_row(titles, style_boldcenter))
# if prev_moy:
# tit_prev_moy = "Moy " + sp
# # col_prev_moy = titles.index(tit_prev_moy)
# tit_moy = "Moy " + sn
# col_moy = titles.index(tit_moy)
# col_abs = titles.index("Abs")
def fmt(x):
"reduit les notes a deux chiffres"
@ -230,13 +232,13 @@ def feuille_preparation_jury(formsemestre_id):
i = 1 # numero etudiant
for etud in etuds:
cells = []
cells.append(ws.make_cell(str(i)))
cells.append(sheet.make_cell(str(i)))
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"):
cells.append(ws.make_cell(etud.code_ine))
cells.append(sheet.make_cell(etud.code_ine))
admission = etud.admission.first()
cells += ws.make_row(
cells += sheet.make_row(
[
etud.id,
etud.civilite_str,
@ -254,50 +256,52 @@ def feuille_preparation_jury(formsemestre_id):
if prev_moy:
for ue_acro in ue_prev_codes:
cells.append(
ws.make_cell(
sheet.make_cell(
fmt(prev_moy_ue.get(ue_acro, {}).get(etud.id, "")), style_note
)
)
co += 1
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
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
co += 2
for ue_acro in ue_codes:
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
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
co += 1
if moy_inter:
cells.append(ws.make_cell(fmt(moy_inter.get(etud.id, "")), style_note))
cells.append(ws.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(fmt(moy_inter.get(etud.id, "")), style_note))
cells.append(sheet.make_cell(str(nbabs.get(etud.id, "")), style_center))
cells.append(sheet.make_cell(str(nbabsjust.get(etud.id, "")), style_center))
if code:
cells.append(ws.make_cell(code.get(etud.id, ""), style_moy))
cells.append(ws.make_cell(autorisations.get(etud.id, ""), style_moy))
cells.append(sheet.make_cell(code.get(etud.id, ""), style_moy))
cells.append(sheet.make_cell(autorisations.get(etud.id, ""), style_moy))
# l.append(assidu.get(etud.id, ''))
ws.append_row(cells)
sheet.append_row(cells)
i += 1
#
ws.append_blank_row()
sheet.append_blank_row()
# Explications des codes
codes = list(sco_codes_parcours.CODES_EXPL.keys())
codes.sort()
ws.append_single_cell_row("Explication des codes")
sheet.append_single_cell_row("Explication des codes")
for code in codes:
ws.append_row(
ws.make_row(["", "", "", code, sco_codes_parcours.CODES_EXPL[code]])
sheet.append_row(
sheet.make_row(["", "", "", code, sco_codes_parcours.CODES_EXPL[code]])
)
ws.append_row(
ws.make_row(
sheet.append_row(
sheet.make_row(
[
"",
"",
@ -308,16 +312,16 @@ def feuille_preparation_jury(formsemestre_id):
)
)
# UE : Correspondances acronyme et titre complet
ws.append_blank_row()
ws.append_single_cell_row("Titre des UE")
sheet.append_blank_row()
sheet.append_single_cell_row("Titre des UE")
if prev_moy:
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):
ws.append_row(ws.make_row(["", "", "", ue["acronyme"], ue["titre"]]))
sheet.append_row(sheet.make_row(["", "", "", ue["acronyme"], ue["titre"]]))
#
ws.append_blank_row()
ws.append_single_cell_row(
sheet.append_blank_row()
sheet.append_single_cell_row(
"Préparé par %s le %s sur %s pour %s"
% (
sco_version.SCONAME,
@ -326,7 +330,7 @@ def feuille_preparation_jury(formsemestre_id):
current_user,
)
)
xls = ws.generate()
xls = sheet.generate()
flash("Feuille préparation jury générée")
return scu.send_file(
xls,

View File

@ -30,6 +30,8 @@
import io
import re
from PIL import Image as PILImage
import reportlab
from reportlab.lib.units import cm, mm
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 flask import g
from app.models.formsemestre import FormSemestre
import app.scodoc.sco_utils as scu
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):
"Ajoute au canvas le frame avec le logo"
if only_on_first_page and int(doc.page) > 1:
return
height = doc.pagesize[1]
@ -147,12 +151,12 @@ def page_header(canvas, doc, logo, preferences, only_on_first_page=False):
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__(
self,
document,
pagesbookmarks={},
pagesbookmarks=None,
author=None,
title=None,
subject=None,
@ -163,7 +167,7 @@ class CourrierIndividuelTemplate(PageTemplate):
template_name="CourrierJuryTemplate",
):
"""Initialise our page template."""
self.pagesbookmarks = pagesbookmarks
self.pagesbookmarks = pagesbookmarks or {}
self.pdfmeta_author = author
self.pdfmeta_title = title
self.pdfmeta_subject = subject
@ -237,32 +241,32 @@ class CourrierIndividuelTemplate(PageTemplate):
width=LOGO_HEADER_WIDTH,
)
def beforeDrawPage(self, canvas, doc):
def beforeDrawPage(self, canv, doc):
"""Draws a logo and an contribution message on each page."""
# ---- Add some meta data and bookmarks
if self.pdfmeta_author:
canvas.setAuthor(SU(self.pdfmeta_author))
canv.setAuthor(SU(self.pdfmeta_author))
if self.pdfmeta_title:
canvas.setTitle(SU(self.pdfmeta_title))
canv.setTitle(SU(self.pdfmeta_title))
if self.pdfmeta_subject:
canvas.setSubject(SU(self.pdfmeta_subject))
canv.setSubject(SU(self.pdfmeta_subject))
bm = self.pagesbookmarks.get(doc.page, None)
if bm != None:
key = bm
txt = SU(bm)
canvas.bookmarkPage(key)
canvas.addOutlineEntry(txt, bm)
canv.bookmarkPage(key)
canv.addOutlineEntry(txt, bm)
# ---- Background image
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]
)
# ---- Header/Footer
if self.with_header:
page_header(
canvas,
canv,
doc,
self.logo_header,
self.preferences,
@ -270,7 +274,7 @@ class CourrierIndividuelTemplate(PageTemplate):
)
if self.with_footer:
page_footer(
canvas,
canv,
doc,
self.logo_footer,
self.preferences,
@ -332,6 +336,39 @@ class PVTemplate(CourrierIndividuelTemplate):
# 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(
formsemestre_id,
etudids=None,
@ -394,8 +431,8 @@ def pdf_lettres_individuelles(
document.addPageTemplates(
CourrierIndividuelTemplate(
document,
author="%s %s (E. Viennet)" % (sco_version.SCONAME, sco_version.SCOVERSION),
title="Lettres décision %s" % sem["titreannee"],
author=f"{sco_version.SCONAME} {sco_version.SCOVERSION} (E. Viennet)",
title=f"Lettres décision {sem['titreannee']}",
subject="Décision jury",
margins=margins,
pagesbookmarks=bookmarks,
@ -410,10 +447,7 @@ def pdf_lettres_individuelles(
def _descr_jury(sem, diplome):
if not diplome:
t = "passage de Semestre %d en Semestre %d" % (
sem["semestre_id"],
sem["semestre_id"] + 1,
)
t = f"""passage de Semestre {sem["semestre_id"]} en Semestre {sem["semestre_id"] + 1}"""
s = "passage de semestre"
else:
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 = FormSemestre.query.get(formsemestre_id)
Se: SituationEtudCursus = decision["Se"]
t, s = _descr_jury(sem, Se.parcours_validated() or not Se.semestre_non_terminal)
objects = []
@ -437,7 +472,7 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None):
style.leading = 18
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["type_jury"] = t # type de jury (passage ou delivrance)
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"] = (
sco_preferences.get_preference("INSTITUTION_CITY", formsemestre_id) or ""
)
if decision["prev_decision_sem"]:
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"])
# fix domicile
if params["domicile"]:
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:
if decision["decisions_ue"] and decision["decisions_ue_descr"]:
params["decision_ue_txt"] = (
@ -567,39 +599,23 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None):
return objects
def _simulate_br(p, para="<para>"):
"""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>
"""
l = re.split(r"<.*?br.*?/>", p)
return ("</para>" + para).join(l)
def add_classic_infos(formsemestre: FormSemestre, params: dict, decision: dict):
"""Ajoute les champs pour les formations classiques, donc avec codes semestres"""
if decision["prev_decision_sem"]:
params["prev_code_descr"] = decision["prev_code_descr"]
params[
"prev_decision_sem_txt"
] = 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):
"cree un paragraphe avec l'image signature"
# cree une image PIL pour avoir la taille (W,H)
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),
)
def add_apc_infos(formsemestre: FormSemestre, params: dict, decision: dict):
"""Ajoute les champs pour les formations APC (BUT), donc avec codes RCUE et année"""
pass # TODO XXX
# ----------------------------------------------

View File

@ -296,7 +296,9 @@ def formsemestre_bulletinetud(
format = format or "html"
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)
if 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:
return flask.abort(404, "argument manquant: formsemestre_id")
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 = {}
if etape_apo:
args["etape_apo"] = etape_apo