forked from ScoDoc/ScoDoc
Diverses améliorations pour faciliter la config BUT. Voir #862
This commit is contained in:
parent
56aa5fbba3
commit
fae9fbdd09
@ -119,6 +119,12 @@ def _build_bulletin_but_infos(
|
|||||||
refcomp = formsemestre.formation.referentiel_competence
|
refcomp = formsemestre.formation.referentiel_competence
|
||||||
if refcomp is None:
|
if refcomp is None:
|
||||||
raise ScoNoReferentielCompetences(formation=formsemestre.formation)
|
raise ScoNoReferentielCompetences(formation=formsemestre.formation)
|
||||||
|
|
||||||
|
warn_html = cursus_but.formsemestre_warning_apc_setup(
|
||||||
|
formsemestre, bulletins_sem.res
|
||||||
|
)
|
||||||
|
if warn_html:
|
||||||
|
raise ScoValueError("<b>Formation mal configurée pour le BUT</b>" + warn_html)
|
||||||
ue_validation_by_niveau = validations_view.get_ue_validation_by_niveau(
|
ue_validation_by_niveau = validations_view.get_ue_validation_by_niveau(
|
||||||
refcomp, etud
|
refcomp, etud
|
||||||
)
|
)
|
||||||
|
@ -23,29 +23,21 @@ from app.comp.res_but import ResultatsSemestreBUT
|
|||||||
from app.comp.res_compat import NotesTableCompat
|
from app.comp.res_compat import NotesTableCompat
|
||||||
|
|
||||||
from app.models.but_refcomp import (
|
from app.models.but_refcomp import (
|
||||||
ApcAnneeParcours,
|
|
||||||
ApcCompetence,
|
ApcCompetence,
|
||||||
ApcNiveau,
|
ApcNiveau,
|
||||||
ApcParcours,
|
ApcParcours,
|
||||||
ApcParcoursNiveauCompetence,
|
|
||||||
ApcReferentielCompetences,
|
ApcReferentielCompetences,
|
||||||
)
|
)
|
||||||
from app.models import Scolog, ScolarAutorisationInscription
|
from app.models.ues import UEParcours
|
||||||
from app.models.but_validations import (
|
from app.models.but_validations import ApcValidationRCUE
|
||||||
ApcValidationAnnee,
|
|
||||||
ApcValidationRCUE,
|
|
||||||
)
|
|
||||||
from app.models.etudiants import Identite
|
from app.models.etudiants import Identite
|
||||||
from app.models.formations import Formation
|
from app.models.formations import Formation
|
||||||
from app.models.formsemestre import FormSemestre, FormSemestreInscription
|
from app.models.formsemestre import FormSemestre
|
||||||
from app.models.ues import UniteEns
|
from app.models.ues import UniteEns
|
||||||
from app.models.validations import ScolarFormSemestreValidation
|
from app.models.validations import ScolarFormSemestreValidation
|
||||||
from app.scodoc import codes_cursus as sco_codes
|
from app.scodoc import codes_cursus as sco_codes
|
||||||
from app.scodoc.codes_cursus import code_ue_validant, CODES_UE_VALIDES, UE_STANDARD
|
from app.scodoc.codes_cursus import code_ue_validant, CODES_UE_VALIDES, UE_STANDARD
|
||||||
|
|
||||||
from app.scodoc import sco_utils as scu
|
|
||||||
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences, ScoValueError
|
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences, ScoValueError
|
||||||
|
|
||||||
from app.scodoc import sco_cursus_dut
|
from app.scodoc import sco_cursus_dut
|
||||||
|
|
||||||
|
|
||||||
@ -440,11 +432,16 @@ def formsemestre_warning_apc_setup(
|
|||||||
"""
|
"""
|
||||||
if not formsemestre.formation.is_apc():
|
if not formsemestre.formation.is_apc():
|
||||||
return ""
|
return ""
|
||||||
|
url_formation = url_for(
|
||||||
|
"notes.ue_table",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
formation_id=formsemestre.formation.id,
|
||||||
|
semestre_idx=formsemestre.semestre_id,
|
||||||
|
)
|
||||||
if formsemestre.formation.referentiel_competence is None:
|
if formsemestre.formation.referentiel_competence is None:
|
||||||
return f"""<div class="formsemestre_status_warning">
|
return f"""<div class="formsemestre_status_warning">
|
||||||
La <a class="stdlink" href="{
|
La <a class="stdlink" href="{url_formation}">formation
|
||||||
url_for("notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formsemestre.formation.id)
|
n'est pas associée à un référentiel de compétence.</a>
|
||||||
}">formation n'est pas associée à un référentiel de compétence.</a>
|
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
H = []
|
H = []
|
||||||
@ -462,7 +459,9 @@ def formsemestre_warning_apc_setup(
|
|||||||
)
|
)
|
||||||
if nb_ues_sans_parcours != nb_ues_tot:
|
if nb_ues_sans_parcours != nb_ues_tot:
|
||||||
H.append(
|
H.append(
|
||||||
f"""Le semestre n'est associé à aucun parcours, mais les UEs de la formation ont des parcours"""
|
"""Le semestre n'est associé à aucun parcours,
|
||||||
|
mais les UEs de la formation ont des parcours
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
# Vérifie les niveaux de chaque parcours
|
# Vérifie les niveaux de chaque parcours
|
||||||
for parcour in formsemestre.parcours or [None]:
|
for parcour in formsemestre.parcours or [None]:
|
||||||
@ -489,7 +488,8 @@ def formsemestre_warning_apc_setup(
|
|||||||
if not H:
|
if not H:
|
||||||
return ""
|
return ""
|
||||||
return f"""<div class="formsemestre_status_warning">
|
return f"""<div class="formsemestre_status_warning">
|
||||||
Problème dans la configuration de la formation:
|
Problème dans la
|
||||||
|
<a class="stdlink" href="{url_formation}">configuration de la formation</a>:
|
||||||
<ul>
|
<ul>
|
||||||
<li>{ '</li><li>'.join(H) }</li>
|
<li>{ '</li><li>'.join(H) }</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -502,6 +502,76 @@ def formsemestre_warning_apc_setup(
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def formation_semestre_niveaux_warning(formation: Formation, semestre_idx: int) -> str:
|
||||||
|
"""Vérifie que tous les niveaux de compétences de cette année de formation
|
||||||
|
ont bien des UEs.
|
||||||
|
Afin de ne pas générer trop de messages, on ne considère que les parcours
|
||||||
|
du référentiel de compétences pour lesquels au moins une UE a été associée.
|
||||||
|
|
||||||
|
Renvoie fragment de html
|
||||||
|
"""
|
||||||
|
annee = (semestre_idx - 1) // 2 + 1 # année BUT
|
||||||
|
ref_comp: ApcReferentielCompetences = formation.referentiel_competence
|
||||||
|
niveaux_sans_ue_by_parcour = {} # { parcour.code : [ ue ... ] }
|
||||||
|
parcours_ids = {
|
||||||
|
uep.parcours_id
|
||||||
|
for uep in UEParcours.query.join(UniteEns).filter_by(
|
||||||
|
formation_id=formation.id, type=UE_STANDARD
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for parcour in ref_comp.parcours:
|
||||||
|
if parcour.id not in parcours_ids:
|
||||||
|
continue # saute parcours associés à aucune UE (tous semestres)
|
||||||
|
niveaux_sans_ue = []
|
||||||
|
niveaux = ApcNiveau.niveaux_annee_de_parcours(parcour, annee, ref_comp)
|
||||||
|
# print(f"\n# Parcours {parcour.code} : {len(niveaux)} niveaux")
|
||||||
|
for niveau in niveaux:
|
||||||
|
ues = [ue for ue in formation.ues if ue.niveau_competence_id == niveau.id]
|
||||||
|
if not ues:
|
||||||
|
niveaux_sans_ue.append(niveau)
|
||||||
|
# print( niveau.competence.titre + " " + str(niveau.ordre) + "\t" + str(ue) )
|
||||||
|
if niveaux_sans_ue:
|
||||||
|
niveaux_sans_ue_by_parcour[parcour.code] = niveaux_sans_ue
|
||||||
|
#
|
||||||
|
H = []
|
||||||
|
for parcour_code, niveaux in niveaux_sans_ue_by_parcour.items():
|
||||||
|
H.append(
|
||||||
|
f"""<li>Parcours {parcour_code} : {
|
||||||
|
len(niveaux)} niveaux sans UEs
|
||||||
|
<span>
|
||||||
|
{ ', '.join( f'{niveau.competence.titre} {niveau.ordre}'
|
||||||
|
for niveau in niveaux
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
# Combien de compétences de tronc commun ?
|
||||||
|
_, niveaux_by_parcours = ref_comp.get_niveaux_by_parcours(annee)
|
||||||
|
nb_niveaux_tc = len(niveaux_by_parcours["TC"])
|
||||||
|
nb_ues_tc = len(
|
||||||
|
formation.query_ues_parcour(None)
|
||||||
|
.filter(UniteEns.semestre_idx == semestre_idx)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
if nb_niveaux_tc != nb_ues_tc:
|
||||||
|
H.append(
|
||||||
|
f"""<li>{nb_niveaux_tc} niveaux de compétences de tronc commun,
|
||||||
|
mais {nb_ues_tc} UEs de tronc commun !</li>"""
|
||||||
|
)
|
||||||
|
|
||||||
|
if H:
|
||||||
|
return f"""<div class="formation_semestre_niveaux_warning">
|
||||||
|
<div>Problèmes détectés à corriger :</div>
|
||||||
|
<ul>
|
||||||
|
{"".join(H)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
return "" # no problem detected
|
||||||
|
|
||||||
|
|
||||||
def ue_associee_au_niveau_du_parcours(
|
def ue_associee_au_niveau_du_parcours(
|
||||||
ues_possibles: list[UniteEns], niveau: ApcNiveau, sem_name: str = "S"
|
ues_possibles: list[UniteEns], niveau: ApcNiveau, sem_name: str = "S"
|
||||||
) -> UniteEns:
|
) -> UniteEns:
|
||||||
|
@ -50,14 +50,11 @@ import traceback
|
|||||||
|
|
||||||
import reportlab
|
import reportlab
|
||||||
from reportlab.platypus import (
|
from reportlab.platypus import (
|
||||||
SimpleDocTemplate,
|
|
||||||
DocIf,
|
DocIf,
|
||||||
Paragraph,
|
Paragraph,
|
||||||
Spacer,
|
|
||||||
Frame,
|
|
||||||
PageBreak,
|
PageBreak,
|
||||||
)
|
)
|
||||||
from reportlab.platypus import Table, TableStyle, Image, KeepInFrame
|
from reportlab.platypus import Table, KeepInFrame
|
||||||
|
|
||||||
from flask import request
|
from flask import request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
@ -213,26 +210,26 @@ class BulletinGenerator:
|
|||||||
story.append(PageBreak()) # insert page break at end
|
story.append(PageBreak()) # insert page break at end
|
||||||
|
|
||||||
return story
|
return story
|
||||||
else:
|
|
||||||
# Generation du document PDF
|
# Generation du document PDF
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
report = io.BytesIO() # in-memory document, no disk file
|
report = io.BytesIO() # in-memory document, no disk file
|
||||||
document = sco_pdf.BaseDocTemplate(report)
|
document = sco_pdf.BaseDocTemplate(report)
|
||||||
document.addPageTemplates(
|
document.addPageTemplates(
|
||||||
sco_pdf.ScoDocPageTemplate(
|
sco_pdf.ScoDocPageTemplate(
|
||||||
document,
|
document,
|
||||||
author="%s %s (E. Viennet) [%s]"
|
author=f"""{sco_version.SCONAME} {
|
||||||
% (sco_version.SCONAME, sco_version.SCOVERSION, self.description),
|
sco_version.SCOVERSION} (E. Viennet) [{self.description}]""",
|
||||||
title=f"""Bulletin {sem["titremois"]} de {etat_civil}""",
|
title=f"""Bulletin {sem["titremois"]} de {etat_civil}""",
|
||||||
subject="Bulletin de note",
|
subject="Bulletin de note",
|
||||||
margins=self.margins,
|
margins=self.margins,
|
||||||
server_name=self.server_name,
|
server_name=self.server_name,
|
||||||
filigranne=self.filigranne,
|
filigranne=self.filigranne,
|
||||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||||
)
|
|
||||||
)
|
)
|
||||||
document.build(story)
|
)
|
||||||
data = report.getvalue()
|
document.build(story)
|
||||||
|
data = report.getvalue()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def buildTableObject(self, P, pdfTableStyle, colWidths):
|
def buildTableObject(self, P, pdfTableStyle, colWidths):
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
from flask.templating import render_template
|
from flask.templating import render_template
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
from app.but import apc_edit_ue
|
from app.but import cursus_but
|
||||||
from app.models import UniteEns, Matiere, Module, FormSemestre, ModuleImpl
|
from app.models import UniteEns, Matiere, Module, FormSemestre, ModuleImpl
|
||||||
from app.models.validations import ScolarFormSemestreValidation
|
from app.models.validations import ScolarFormSemestreValidation
|
||||||
from app.scodoc import codes_cursus
|
from app.scodoc import codes_cursus
|
||||||
@ -101,18 +101,26 @@ def html_edit_formation_apc(
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html_ue_warning = {
|
||||||
|
semestre_idx: cursus_but.formation_semestre_niveaux_warning(
|
||||||
|
formation, semestre_idx
|
||||||
|
)
|
||||||
|
for semestre_idx in semestre_ids
|
||||||
|
}
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
render_template(
|
render_template(
|
||||||
"pn/form_ues.j2",
|
"pn/form_ues.j2",
|
||||||
formation=formation,
|
|
||||||
semestre_ids=semestre_ids,
|
|
||||||
editable=editable,
|
|
||||||
tag_editable=tag_editable,
|
|
||||||
icons=icons,
|
|
||||||
ues_by_sem=ues_by_sem,
|
|
||||||
ects_by_sem=ects_by_sem,
|
|
||||||
scu=scu,
|
|
||||||
codes_cursus=codes_cursus,
|
codes_cursus=codes_cursus,
|
||||||
|
ects_by_sem=ects_by_sem,
|
||||||
|
editable=editable,
|
||||||
|
formation=formation,
|
||||||
|
html_ue_warning=html_ue_warning,
|
||||||
|
icons=icons,
|
||||||
|
scu=scu,
|
||||||
|
semestre_ids=semestre_ids,
|
||||||
|
tag_editable=tag_editable,
|
||||||
|
ues_by_sem=ues_by_sem,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
for semestre_idx in semestre_ids:
|
for semestre_idx in semestre_ids:
|
||||||
|
@ -892,7 +892,9 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
|||||||
<form>
|
<form>
|
||||||
<input type="checkbox" class="sco_tag_checkbox"
|
<input type="checkbox" class="sco_tag_checkbox"
|
||||||
{'checked' if show_tags else ''}
|
{'checked' if show_tags else ''}
|
||||||
> Montrer les tags des modules voire en ajouter <i>(ceux correspondant aux titres des compétences étant ajoutés par défaut)</i></input>
|
> Montrer les tags des modules voire en ajouter
|
||||||
|
<i>(ceux correspondant aux titres des compétences étant ajoutés par défaut)</i>
|
||||||
|
</input>
|
||||||
</form>
|
</form>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -211,8 +211,6 @@ def do_formsemestre_desinscription(
|
|||||||
"""Désinscription d'un étudiant.
|
"""Désinscription d'un étudiant.
|
||||||
Si semestre extérieur et dernier inscrit, suppression de ce semestre.
|
Si semestre extérieur et dernier inscrit, suppression de ce semestre.
|
||||||
"""
|
"""
|
||||||
from app.scodoc import sco_formsemestre_edit
|
|
||||||
|
|
||||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
etud = Identite.get_etud(etudid)
|
etud = Identite.get_etud(etudid)
|
||||||
# -- check lock
|
# -- check lock
|
||||||
@ -258,17 +256,14 @@ def do_formsemestre_desinscription(
|
|||||||
sco_cache.invalidate_formsemestre(formsemestre_id=formsemestre_id)
|
sco_cache.invalidate_formsemestre(formsemestre_id=formsemestre_id)
|
||||||
# --- Semestre extérieur
|
# --- Semestre extérieur
|
||||||
if formsemestre.modalite == "EXT":
|
if formsemestre.modalite == "EXT":
|
||||||
inscrits = do_formsemestre_inscription_list(
|
if 0 == len(formsemestre.inscriptions):
|
||||||
args={"formsemestre_id": formsemestre_id}
|
|
||||||
)
|
|
||||||
nbinscrits = len(inscrits)
|
|
||||||
if nbinscrits == 0:
|
|
||||||
log(
|
log(
|
||||||
f"""do_formsemestre_desinscription:
|
f"""do_formsemestre_desinscription:
|
||||||
suppression du semestre extérieur {formsemestre}"""
|
suppression du semestre extérieur {formsemestre}"""
|
||||||
)
|
)
|
||||||
flash("Semestre exterieur supprimé")
|
db.session.delete(formsemestre)
|
||||||
sco_formsemestre_edit.do_formsemestre_delete(formsemestre_id)
|
db.session.commit()
|
||||||
|
flash(f"Semestre extérieur supprimé: {formsemestre.titre_annee()}")
|
||||||
|
|
||||||
logdb(
|
logdb(
|
||||||
cnx,
|
cnx,
|
||||||
@ -587,26 +582,29 @@ def formsemestre_inscription_option(etudid, formsemestre_id):
|
|||||||
ue_id = ue.id
|
ue_id = ue.id
|
||||||
ue_descr = ue.acronyme
|
ue_descr = ue.acronyme
|
||||||
if ue.type != UE_STANDARD:
|
if ue.type != UE_STANDARD:
|
||||||
ue_descr += " <em>%s</em>" % UE_TYPE_NAME[ue.type]
|
ue_descr += f" <em>{UE_TYPE_NAME[ue.type]}</em>"
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
||||||
if ue_status and ue_status["is_capitalized"]:
|
if ue_status and ue_status["is_capitalized"]:
|
||||||
sem_origin = sco_formsemestre.get_formsemestre(ue_status["formsemestre_id"])
|
sem_origin = sco_formsemestre.get_formsemestre(ue_status["formsemestre_id"])
|
||||||
ue_descr += (
|
ue_descr += f"""
|
||||||
' <a class="discretelink" href="formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s" title="%s">(capitalisée le %s)'
|
<a class="discretelink" href="{ url_for(
|
||||||
% (
|
'notes.formsemestre_bulletinetud', scodoc_dept=g.scodoc_dept,
|
||||||
sem_origin["formsemestre_id"],
|
formsemestre_id=sem_origin["formsemestre_id"],
|
||||||
etudid,
|
etudid = etudid
|
||||||
sem_origin["titreannee"],
|
)}" title="{sem_origin['titreannee']}">(capitalisée le {
|
||||||
ndb.DateISOtoDMY(ue_status["event_date"]),
|
ndb.DateISOtoDMY(ue_status["event_date"])
|
||||||
)
|
})
|
||||||
)
|
"""
|
||||||
descr.append(
|
descr.append(
|
||||||
(
|
(
|
||||||
"sec_%s" % ue_id,
|
f"sec_{ue_id}",
|
||||||
{
|
{
|
||||||
"input_type": "separator",
|
"input_type": "separator",
|
||||||
"title": """<b>%s :</b> <a href="#" onclick="chkbx_select('%s', true);">inscrire</a> | <a href="#" onclick="chkbx_select('%s', false);">désinscrire</a> à tous les modules"""
|
"title": f"""<b>{ue_descr} :</b>
|
||||||
% (ue_descr, ue_id, ue_id),
|
<a href="#" onclick="chkbx_select('{ue_id}', true);">inscrire</a> | <a
|
||||||
|
href="#" onclick="chkbx_select('{ue_id}', false);">désinscrire</a>
|
||||||
|
à tous les modules
|
||||||
|
""",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -776,9 +774,7 @@ def do_moduleimpl_incription_options(
|
|||||||
# verifie que ce module existe bien
|
# verifie que ce module existe bien
|
||||||
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
||||||
if len(mods) != 1:
|
if len(mods) != 1:
|
||||||
raise ScoValueError(
|
raise ScoValueError(f"inscription: invalid moduleimpl_id: {moduleimpl_id}")
|
||||||
"inscription: invalid moduleimpl_id: %s" % moduleimpl_id
|
|
||||||
)
|
|
||||||
mod = mods[0]
|
mod = mods[0]
|
||||||
sco_moduleimpl.do_moduleimpl_inscription_create(
|
sco_moduleimpl.do_moduleimpl_inscription_create(
|
||||||
{"moduleimpl_id": moduleimpl_id, "etudid": etudid},
|
{"moduleimpl_id": moduleimpl_id, "etudid": etudid},
|
||||||
@ -790,7 +786,7 @@ def do_moduleimpl_incription_options(
|
|||||||
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
||||||
if len(mods) != 1:
|
if len(mods) != 1:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"desinscription: invalid moduleimpl_id: %s" % moduleimpl_id
|
f"desinscription: invalid moduleimpl_id: {moduleimpl_id}"
|
||||||
)
|
)
|
||||||
mod = mods[0]
|
mod = mods[0]
|
||||||
inscr = sco_moduleimpl.do_moduleimpl_inscription_list(
|
inscr = sco_moduleimpl.do_moduleimpl_inscription_list(
|
||||||
@ -798,8 +794,7 @@ def do_moduleimpl_incription_options(
|
|||||||
)
|
)
|
||||||
if not inscr:
|
if not inscr:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"pas inscrit a ce module ! (etudid=%s, moduleimpl_id=%s)"
|
f"pas inscrit a ce module ! (etudid={etudid}, moduleimpl_id={moduleimpl_id})"
|
||||||
% (etudid, moduleimpl_id)
|
|
||||||
)
|
)
|
||||||
oid = inscr[0]["moduleimpl_inscription_id"]
|
oid = inscr[0]["moduleimpl_inscription_id"]
|
||||||
sco_moduleimpl.do_moduleimpl_inscription_delete(
|
sco_moduleimpl.do_moduleimpl_inscription_delete(
|
||||||
@ -808,11 +803,13 @@ def do_moduleimpl_incription_options(
|
|||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(),
|
html_sco_header.sco_header(),
|
||||||
"""<h3>Modifications effectuées</h3>
|
f"""<h3>Modifications effectuées</h3>
|
||||||
<p><a class="stdlink" href="%s">
|
<p><a class="stdlink" href="{
|
||||||
Retour à la fiche étudiant</a></p>
|
url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid)
|
||||||
"""
|
}">
|
||||||
% url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid),
|
Retour à la fiche étudiant</a>
|
||||||
|
</p>
|
||||||
|
""",
|
||||||
html_sco_header.sco_footer(),
|
html_sco_header.sco_footer(),
|
||||||
]
|
]
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
@ -856,49 +853,59 @@ def formsemestre_inscrits_ailleurs(formsemestre_id):
|
|||||||
"""Page listant les étudiants inscrits dans un autre semestre
|
"""Page listant les étudiants inscrits dans un autre semestre
|
||||||
dont les dates recouvrent le semestre indiqué.
|
dont les dates recouvrent le semestre indiqué.
|
||||||
"""
|
"""
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
"Inscriptions multiples parmi les étudiants du semestre ",
|
"Inscriptions multiples parmi les étudiants du semestre ",
|
||||||
|
init_qtip=True,
|
||||||
|
javascripts=["js/etud_info.js"],
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
insd = list_inscrits_ailleurs(formsemestre_id)
|
insd = list_inscrits_ailleurs(formsemestre_id)
|
||||||
# liste ordonnée par nom
|
# liste ordonnée par nom
|
||||||
etudlist = [
|
etudlist = [Identite.get_etud(etudid) for etudid, sems in insd.items() if sems]
|
||||||
sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
etudlist.sort(key=lambda x: x.sort_key)
|
||||||
for etudid in insd.keys()
|
|
||||||
if insd[etudid]
|
|
||||||
]
|
|
||||||
etudlist.sort(key=lambda x: x["nom"])
|
|
||||||
if etudlist:
|
if etudlist:
|
||||||
H.append("<ul>")
|
H.append("<ul>")
|
||||||
for etud in etudlist:
|
for etud in etudlist:
|
||||||
H.append(
|
H.append(
|
||||||
'<li><a href="%s" class="discretelink">%s</a> : '
|
f"""<li><a id="{etud.id}" class="discretelink etudinfo"
|
||||||
% (
|
href={
|
||||||
url_for(
|
url_for(
|
||||||
"scolar.fiche_etud",
|
"scolar.fiche_etud",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
etudid=etud["etudid"],
|
etudid=etud.id,
|
||||||
),
|
)
|
||||||
etud["nomprenom"],
|
}
|
||||||
)
|
>{etud.nomprenom}</a> :
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
l = []
|
l = []
|
||||||
for s in insd[etud["etudid"]]:
|
for s in insd[etud.id]:
|
||||||
l.append(
|
l.append(
|
||||||
'<a class="discretelink" href="formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titremois)s</a>'
|
f"""<a class="discretelink" href="{
|
||||||
% s
|
url_for('notes.formsemestre_status',
|
||||||
|
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id
|
||||||
|
)}">{s['titremois']}</a>"""
|
||||||
)
|
)
|
||||||
H.append(", ".join(l))
|
H.append(", ".join(l))
|
||||||
H.append("</li>")
|
H.append("</li>")
|
||||||
H.append("</ul>")
|
|
||||||
H.append("<p>Total: %d étudiants concernés.</p>" % len(etudlist))
|
|
||||||
H.append(
|
H.append(
|
||||||
"""<p class="help">Ces étudiants sont inscrits dans le semestre sélectionné et aussi dans d'autres semestres qui se déroulent en même temps ! <br>Sauf exception, cette situation est anormale:</p>
|
f"""
|
||||||
|
</ul>
|
||||||
|
<p><b>Total: {len(etudlist)} étudiants concernés.</b></p>
|
||||||
|
|
||||||
|
<p class="help">Ces étudiants sont inscrits dans le semestre sélectionné et aussi
|
||||||
|
dans d'autres semestres qui se déroulent en même temps !
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Sauf exception, cette situation est anormale:</b>
|
||||||
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>vérifier que les dates des semestres se suivent sans se chevaucher</li>
|
<li>vérifier que les dates des semestres se suivent <em>sans se chevaucher</em>
|
||||||
<li>ou si besoin désinscrire le(s) étudiant(s) de l'un des semestres (via leurs fiches individuelles).</li>
|
</li>
|
||||||
|
<li>ou bien si besoin désinscrire le(s) étudiant(s) de l'un des semestres
|
||||||
|
(via leurs fiches individuelles).
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -110,12 +110,13 @@ def formsemestre_synchro_etuds(
|
|||||||
raise ScoValueError("opération impossible: semestre verrouille")
|
raise ScoValueError("opération impossible: semestre verrouille")
|
||||||
if not sem["etapes"]:
|
if not sem["etapes"]:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"""opération impossible: ce semestre n'a pas de code étape
|
f"""opération impossible: ce semestre n'a pas de code étape
|
||||||
(voir "<a href="formsemestre_editwithmodules?formsemestre_id=%(formsemestre_id)s">Modifier ce semestre</a>")
|
(voir <a class="stdlink" href="{
|
||||||
|
url_for('notes.formsemestre_editwithmodules',
|
||||||
|
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id)
|
||||||
|
}">Modifier ce semestre</a>)
|
||||||
"""
|
"""
|
||||||
% sem
|
|
||||||
)
|
)
|
||||||
header = html_sco_header.sco_header(page_title="Synchronisation étudiants")
|
|
||||||
footer = html_sco_header.sco_footer()
|
footer = html_sco_header.sco_footer()
|
||||||
base_url = url_for(
|
base_url = url_for(
|
||||||
"notes.formsemestre_synchro_etuds",
|
"notes.formsemestre_synchro_etuds",
|
||||||
@ -166,7 +167,13 @@ def formsemestre_synchro_etuds(
|
|||||||
suffix=scu.XLSX_SUFFIX,
|
suffix=scu.XLSX_SUFFIX,
|
||||||
)
|
)
|
||||||
|
|
||||||
H = [header]
|
H = [
|
||||||
|
html_sco_header.sco_header(
|
||||||
|
page_title="Synchronisation étudiants",
|
||||||
|
init_qtip=True,
|
||||||
|
javascripts=["js/etud_info.js"],
|
||||||
|
)
|
||||||
|
]
|
||||||
if not submitted:
|
if not submitted:
|
||||||
H += _build_page(
|
H += _build_page(
|
||||||
sem,
|
sem,
|
||||||
|
@ -2411,6 +2411,29 @@ div.formation_list_ues_titre {
|
|||||||
color: #eee;
|
color: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.formation_semestre_niveaux_warning {
|
||||||
|
font-weight: bold;
|
||||||
|
color: red;
|
||||||
|
padding: 4px;
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-left: 24px;
|
||||||
|
margin-right: 24px;
|
||||||
|
background-color: yellow;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
div.formation_semestre_niveaux_warning div {
|
||||||
|
color: black;
|
||||||
|
font-size: 110%;
|
||||||
|
}
|
||||||
|
div.formation_semestre_niveaux_warning ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
div.formation_semestre_niveaux_warning ul li:before {
|
||||||
|
content: '⚠️';
|
||||||
|
margin-right: 10px; /* Adjust space between emoji and text */
|
||||||
|
}
|
||||||
|
|
||||||
div.formation_list_modules,
|
div.formation_list_modules,
|
||||||
div.formation_list_ues {
|
div.formation_list_ues {
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
@ -2426,6 +2449,7 @@ div.formation_list_ues {
|
|||||||
}
|
}
|
||||||
|
|
||||||
div.formation_list_ues_content {
|
div.formation_list_ues_content {
|
||||||
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.formation_list_modules {
|
div.formation_list_modules {
|
||||||
@ -2508,7 +2532,13 @@ div.formation_parcs > div {
|
|||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 4px 8px;
|
padding: 2px 6px;
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
div.formation_parcs > div.ue_tc {
|
||||||
|
color: black;
|
||||||
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.formation_parcs > div.focus {
|
div.formation_parcs > div.focus {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<div class="formation_list_ues_titre">Unités d'Enseignement
|
<div class="formation_list_ues_titre">Unités d'Enseignement
|
||||||
semestre {{semestre_idx}} - {{ects_by_sem[semestre_idx] | safe}} ECTS
|
semestre {{semestre_idx}} - {{ects_by_sem[semestre_idx] | safe}} ECTS
|
||||||
</div>
|
</div>
|
||||||
|
{{ html_ue_warning[semestre_idx] | safe }}
|
||||||
<div class="formation_list_ues_content">
|
<div class="formation_list_ues_content">
|
||||||
<ul class="apc_ue_list">
|
<ul class="apc_ue_list">
|
||||||
{% for ue in ues_by_sem[semestre_idx] %}
|
{% for ue in ues_by_sem[semestre_idx] %}
|
||||||
@ -62,6 +63,8 @@
|
|||||||
<div class="formation_parcs">
|
<div class="formation_parcs">
|
||||||
{% for parc in ue.parcours %}
|
{% for parc in ue.parcours %}
|
||||||
<div>{{ parc.code }}</div>
|
<div>{{ parc.code }}</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="ue_tc" title="aucun parcours">Tronc Commun</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
Loading…
Reference in New Issue
Block a user