Modernisation code démission/défaillance...

This commit is contained in:
Emmanuel Viennet 2022-09-30 22:43:39 +02:00
parent a3e4c34745
commit 4f87f22586
22 changed files with 192 additions and 168 deletions

View File

@ -926,7 +926,7 @@ class ResultatsSemestre(ResultatsCache):
group = None # group (dict) de l'étudiant dans cette partition group = None # group (dict) de l'étudiant dans cette partition
# dans NotesTableCompat, à revoir # dans NotesTableCompat, à revoir
etud_etat = self.get_etud_etat(row["etudid"]) etud_etat = self.get_etud_etat(row["etudid"])
if etud_etat == "D": if etud_etat == scu.DEMISSION:
gr_name = "Dém." gr_name = "Dém."
row["_tr_class"] = "dem" row["_tr_class"] = "dem"
elif etud_etat == DEF: elif etud_etat == DEF:

View File

@ -156,8 +156,16 @@ class ScolarEvent(db.Model):
db.Integer, db.Integer,
db.ForeignKey("notes_formsemestre.id"), db.ForeignKey("notes_formsemestre.id"),
) )
etud = db.relationship("Identite", lazy="select", backref="events", uselist=False)
formsemestre = db.relationship(
"FormSemestre", lazy="select", uselist=False, foreign_keys=[formsemestre_id]
)
def to_dict(self) -> dict: def to_dict(self) -> dict:
"as a dict"
d = dict(self.__dict__) d = dict(self.__dict__)
d.pop("_sa_instance_state", None) d.pop("_sa_instance_state", None)
return d return d
def __repr__(self) -> str:
return f"{self.__class__.__name__}({self.event_type}, {self.event_date.isoformat()}, {self.formsemestre})"

View File

@ -41,10 +41,11 @@ from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre from app.models import FormSemestre
from app.models.moduleimpls import ModuleImpl from app.models.moduleimpls import ModuleImpl
from app.pe import pe_tagtable
from app.scodoc import sco_codes_parcours from app.scodoc import sco_codes_parcours
from app.scodoc import sco_tag_module from app.scodoc import sco_tag_module
from app.pe import pe_tagtable from app.scodoc import sco_utils as scu
class SemestreTag(pe_tagtable.TableTag): class SemestreTag(pe_tagtable.TableTag):
@ -103,7 +104,7 @@ class SemestreTag(pe_tagtable.TableTag):
self.inscrlist = [ self.inscrlist = [
etud etud
for etud in self.nt.inscrlist for etud in self.nt.inscrlist
if self.nt.get_etud_etat(etud["etudid"]) == "I" if self.nt.get_etud_etat(etud["etudid"]) == scu.INSCRIT
] ]
self.identdict = { self.identdict = {
etudid: ident etudid: ident

View File

@ -411,9 +411,9 @@ class NotesTable:
def get_etud_etat_html(self, etudid): def get_etud_etat_html(self, etudid):
etat = self.inscrdict[etudid]["etat"] etat = self.inscrdict[etudid]["etat"]
if etat == "I": if etat == scu.INSCRIT:
return "" return ""
elif etat == "D": elif etat == scu.DEMISSION:
return ' <font color="red">(DEMISSIONNAIRE)</font> ' return ' <font color="red">(DEMISSIONNAIRE)</font> '
elif etat == DEF: elif etat == DEF:
return ' <font color="red">(DEFAILLANT)</font> ' return ' <font color="red">(DEFAILLANT)</font> '
@ -465,7 +465,7 @@ class NotesTable:
vals = [] vals = []
for etudid in self.get_etudids(): for etudid in self.get_etudids():
# saute les demissionnaires et les défaillants: # saute les demissionnaires et les défaillants:
if self.inscrdict[etudid]["etat"] != "I": if self.inscrdict[etudid]["etat"] != scu.INSCRIT:
continue continue
val = moys.get(etudid, None) # None si non inscrit val = moys.get(etudid, None) # None si non inscrit
try: try:
@ -507,8 +507,8 @@ class NotesTable:
for t in T: for t in T:
etudid = t[-1] etudid = t[-1]
# saute les demissionnaires et les défaillants: # saute les demissionnaires et les défaillants:
if self.inscrdict[etudid]["etat"] != "I": if self.inscrdict[etudid]["etat"] != scu.INSCRIT:
if self.inscrdict[etudid]["etat"] == "D": if self.inscrdict[etudid]["etat"] == scu.DEMISSION:
nb_dem += 1 nb_dem += 1
if self.inscrdict[etudid]["etat"] == DEF: if self.inscrdict[etudid]["etat"] == DEF:
nb_def += 1 nb_def += 1

View File

@ -435,11 +435,11 @@ def get_appreciations_list(formsemestre_id: int, etudid: int) -> dict:
def _get_etud_etat_html(etat: str) -> str: def _get_etud_etat_html(etat: str) -> str:
"""chaine html représentant l'état (backward compat sco7)""" """chaine html représentant l'état (backward compat sco7)"""
if etat == scu.INSCRIT: # "I" if etat == scu.INSCRIT:
return "" return ""
elif etat == scu.DEMISSION: # "D" elif etat == scu.DEMISSION:
return ' <font color="red">(DEMISSIONNAIRE)</font> ' return ' <font color="red">(DEMISSIONNAIRE)</font> '
elif etat == scu.DEF: # "DEF" elif etat == scu.DEF:
return ' <font color="red">(DEFAILLANT)</font> ' return ' <font color="red">(DEFAILLANT)</font> '
else: else:
return f' <font color="red">({etat})</font> ' return f' <font color="red">({etat})</font> '

View File

@ -360,7 +360,7 @@ class SituationEtudCursusClassic(SituationEtudCursus):
cur_begin_date = self.sem["dateord"] cur_begin_date = self.sem["dateord"]
p = [] p = []
for s in self.sems: for s in self.sems:
if s["ins"]["etat"] == "D": if s["ins"]["etat"] == scu.DEMISSION:
dem = " (dem.)" dem = " (dem.)"
else: else:
dem = "" dem = ""

View File

@ -1010,7 +1010,7 @@ def descr_situation_etud(etudid: int, ne="") -> str:
situation = "non inscrit" + ne situation = "non inscrit" + ne
else: else:
sem = sco_formsemestre.get_formsemestre(r["formsemestre_id"]) sem = sco_formsemestre.get_formsemestre(r["formsemestre_id"])
if r["etat"] == "I": if r["etat"] == scu.INSCRIT:
situation = "inscrit%s en %s" % (ne, sem["titremois"]) situation = "inscrit%s en %s" % (ne, sem["titremois"])
# Cherche la date d'inscription dans scolar_events: # Cherche la date d'inscription dans scolar_events:
events = scolar_events_list( events = scolar_events_list(

View File

@ -117,7 +117,7 @@ def formsemestre_ext_create_form(etudid, formsemestre_id):
# Les autres situations (eg redoublements en changeant d'établissement) # Les autres situations (eg redoublements en changeant d'établissement)
# doivent être gérées par les validations de semestres "antérieurs" # doivent être gérées par les validations de semestres "antérieurs"
insem = sco_formsemestre_inscriptions.do_formsemestre_inscription_list( insem = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
args={"etudid": etudid, "etat": "I"} args={"etudid": etudid, "etat": scu.INSCRIT}
) )
semlist = [sco_formsemestre.get_formsemestre(i["formsemestre_id"]) for i in insem] semlist = [sco_formsemestre.get_formsemestre(i["formsemestre_id"]) for i in insem]
existing_semestre_ids = {s["semestre_id"] for s in semlist} existing_semestre_ids = {s["semestre_id"] for s in semlist}

View File

@ -32,11 +32,13 @@ import time
import flask import flask
from flask import flash, url_for, g, request from flask import flash, url_for, g, request
from app import db
from app.comp import res_sem from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat from app.comp.res_compat import NotesTableCompat
from app.models import Formation, FormSemestre, FormSemestreInscription from app.models import Formation, FormSemestre, FormSemestreInscription, Scolog
from app.models.etudiants import Identite from app.models.etudiants import Identite
from app.models.groups import GroupDescr from app.models.groups import GroupDescr
from app.models.validations import ScolarEvent
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app import log from app import log
from app.scodoc.scolog import logdb from app.scodoc.scolog import logdb
@ -77,7 +79,7 @@ def do_formsemestre_inscription_listinscrits(formsemestre_id):
if r is None: if r is None:
# retreive list # retreive list
r = do_formsemestre_inscription_list( r = do_formsemestre_inscription_list(
args={"formsemestre_id": formsemestre_id, "etat": "I"} args={"formsemestre_id": formsemestre_id, "etat": scu.INSCRIT}
) )
sco_cache.SemInscriptionsCache.set(formsemestre_id, r) sco_cache.SemInscriptionsCache.set(formsemestre_id, r)
return r return r
@ -133,36 +135,51 @@ def do_formsemestre_demission(
etudid, etudid,
formsemestre_id, formsemestre_id,
event_date=None, event_date=None,
etat_new="D", # 'D' or DEF etat_new=scu.DEMISSION, # DEMISSION or DEF
operation_method="demEtudiant", operation_method="dem_etudiant",
event_type="DEMISSION", event_type="DEMISSION",
): ):
"Démission ou défaillance d'un étudiant" "Démission ou défaillance d'un étudiant"
# marque 'D' ou DEF dans l'inscription au semestre et ajoute # marque 'D' ou DEF dans l'inscription au semestre et ajoute
# un "evenement" scolarite # un "evenement" scolarite
cnx = ndb.GetDBConnexion() if etat_new not in (scu.DEF, scu.DEMISSION):
raise ScoValueError("nouveau code d'état invalide")
try:
event_date_iso = ndb.DateDMYtoISO(event_date)
except ValueError as exc:
raise ScoValueError("format de date invalide") from exc
etud: Identite = Identite.query.filter_by(
id=etudid, dept_id=g.scodoc_dept_id
).first_or_404()
# check lock # check lock
sem = sco_formsemestre.get_formsemestre(formsemestre_id) formsemestre: FormSemestre = FormSemestre.query.filter_by(
if not sem["etat"]: id=formsemestre_id, dept_id=g.scodoc_dept_id
).first_or_404()
if not formsemestre.etat:
raise ScoValueError("Modification impossible: semestre verrouille") raise ScoValueError("Modification impossible: semestre verrouille")
# #
ins = do_formsemestre_inscription_list( if formsemestre_id not in (inscr.formsemestre_id for inscr in etud.inscriptions()):
{"etudid": etudid, "formsemestre_id": formsemestre_id} raise ScoValueError("étudiant non inscrit dans ce semestre !")
)[0] inscr = next(
if not ins: inscr
raise ScoException("etudiant non inscrit ?!") for inscr in etud.inscriptions()
ins["etat"] = etat_new if inscr.formsemestre_id == formsemestre_id
do_formsemestre_inscription_edit(args=ins, formsemestre_id=formsemestre_id)
logdb(cnx, method=operation_method, etudid=etudid)
sco_etud.scolar_events_create(
cnx,
args={
"etudid": etudid,
"event_date": event_date,
"formsemestre_id": formsemestre_id,
"event_type": event_type,
},
) )
inscr.etat = etat_new
db.session.add(inscr)
Scolog.logdb(method=operation_method, etudid=etudid)
event = ScolarEvent(
etudid=etudid,
event_date=event_date_iso,
formsemestre_id=formsemestre_id,
event_type=event_type,
)
db.session.add(event)
db.session.commit()
if etat_new == scu.DEMISSION:
flash("Démission enregistrée")
elif etat_new == scu.DEF:
flash("Défaillance enregistrée")
def do_formsemestre_inscription_edit(args=None, formsemestre_id=None): def do_formsemestre_inscription_edit(args=None, formsemestre_id=None):
@ -250,7 +267,7 @@ def do_formsemestre_inscription_with_modules(
formsemestre_id, formsemestre_id,
etudid, etudid,
group_ids=[], group_ids=[],
etat="I", etat=scu.INSCRIT,
etape=None, etape=None,
method="inscription_with_modules", method="inscription_with_modules",
): ):
@ -467,7 +484,7 @@ def formsemestre_inscription_with_modules(
formsemestre_id, formsemestre_id,
etudid, etudid,
group_ids=group_ids, group_ids=group_ids,
etat="I", etat=scu.INSCRIT,
method="formsemestre_inscription_with_modules", method="formsemestre_inscription_with_modules",
) )
return flask.redirect( return flask.redirect(

View File

@ -191,11 +191,11 @@ def formsemestre_validation_etud_form(
) )
etud_etat = nt.get_etud_etat(etudid) etud_etat = nt.get_etud_etat(etudid)
if etud_etat == "D": if etud_etat == scu.DEMISSION:
H.append('<div class="ue_warning"><span>Etudiant démissionnaire</span></div>') H.append('<div class="ue_warning"><span>Etudiant démissionnaire</span></div>')
if etud_etat == DEF: if etud_etat == scu.DEF:
H.append('<div class="ue_warning"><span>Etudiant défaillant</span></div>') H.append('<div class="ue_warning"><span>Etudiant défaillant</span></div>')
if etud_etat != "I": if etud_etat != scu.INSCRIT:
H.append( H.append(
tf_error_message( tf_error_message(
f"""Impossible de statuer sur cet étudiant: f"""Impossible de statuer sur cet étudiant:
@ -357,7 +357,7 @@ def formsemestre_validation_etud_form(
H.append( H.append(
f"""<div class="link_defaillance">Ou <a class="stdlink" href="{ f"""<div class="link_defaillance">Ou <a class="stdlink" href="{
url_for("scolar.formDef", scodoc_dept=g.scodoc_dept, etudid=etudid, url_for("scolar.form_def", scodoc_dept=g.scodoc_dept, etudid=etudid,
formsemestre_id=formsemestre_id) formsemestre_id=formsemestre_id)
}">déclarer l'étudiant comme défaillant dans ce semestre</a></div>""" }">déclarer l'étudiant comme défaillant dans ce semestre</a></div>"""
) )
@ -910,7 +910,7 @@ def do_formsemestre_validation_auto(formsemestre_id):
)[0] )[0]
# Conditions pour validation automatique: # Conditions pour validation automatique:
if ins["etat"] == "I" and ( if ins["etat"] == scu.INSCRIT and (
( (
(not Se.prev) (not Se.prev)
or ( or (

View File

@ -308,9 +308,9 @@ def get_group_infos(group_id, etat=None): # was _getlisteetud
# add human readable description of state: # add human readable description of state:
nbdem = 0 nbdem = 0
for t in members: for t in members:
if t["etat"] == "I": if t["etat"] == scu.INSCRIT:
t["etath"] = "" # etudiant inscrit, ne l'indique pas dans la liste HTML t["etath"] = "" # etudiant inscrit, ne l'indique pas dans la liste HTML
elif t["etat"] == "D": elif t["etat"] == scu.DEMISSION:
events = sco_etud.scolar_events_list( events = sco_etud.scolar_events_list(
cnx, cnx,
args={ args={

View File

@ -545,7 +545,7 @@ def _import_one_student(
args["description"] = "(infos admission)" args["description"] = "(infos admission)"
_ = sco_etud.adresse_create(cnx, args) _ = sco_etud.adresse_create(cnx, args)
# Inscription au semestre # Inscription au semestre
args["etat"] = "I" # etat insc. semestre args["etat"] = scu.INSCRIT # etat insc. semestre
if formsemestre_id: if formsemestre_id:
args["formsemestre_id"] = formsemestre_id args["formsemestre_id"] = formsemestre_id
else: else:
@ -576,7 +576,7 @@ def _import_one_student(
int(args["formsemestre_id"]), int(args["formsemestre_id"]),
etudid, etudid,
group_ids, group_ids,
etat="I", etat=scu.INSCRIT,
method="import_csv_file", method="import_csv_file",
) )
return args["formsemestre_id"] return args["formsemestre_id"]

View File

@ -175,12 +175,12 @@ def do_inscrit(sem, etudids, inscrit_groupes=False):
(la liste doit avoir été vérifiée au préalable) (la liste doit avoir été vérifiée au préalable)
En option: inscrit aux mêmes groupes que dans le semestre origine En option: inscrit aux mêmes groupes que dans le semestre origine
""" """
log("do_inscrit (inscrit_groupes=%s): %s" % (inscrit_groupes, etudids)) log(f"do_inscrit (inscrit_groupes={inscrit_groupes}): {etudids}")
for etudid in etudids: for etudid in etudids:
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
sem["formsemestre_id"], sem["formsemestre_id"],
etudid, etudid,
etat="I", etat=scu.INSCRIT,
method="formsemestre_inscr_passage", method="formsemestre_inscr_passage",
) )
if inscrit_groupes: if inscrit_groupes:

View File

@ -325,11 +325,11 @@ def _make_table_notes(
if etud is None: if etud is None:
continue continue
if etat == "I": # si inscrit, indique groupe if etat == scu.INSCRIT: # si inscrit, indique groupe
groups = sco_groups.get_etud_groups(etudid, modimpl_o["formsemestre_id"]) groups = sco_groups.get_etud_groups(etudid, modimpl_o["formsemestre_id"])
grc = sco_groups.listgroups_abbrev(groups) grc = sco_groups.listgroups_abbrev(groups)
else: else:
if etat == "D": if etat == scu.DEMISSION:
grc = "DEM" # attention: ce code est re-ecrit plus bas, ne pas le changer (?) grc = "DEM" # attention: ce code est re-ecrit plus bas, ne pas le changer (?)
css_row_class = "etuddem" css_row_class = "etuddem"
else: else:

View File

@ -75,18 +75,18 @@ def _menuScolarite(authuser, sem, etudid):
if ins["etat"] != "D": if ins["etat"] != "D":
dem_title = "Démission" dem_title = "Démission"
dem_url = "scolar.formDem" dem_url = "scolar.form_dem"
else: else:
dem_title = "Annuler la démission" dem_title = "Annuler la démission"
dem_url = "scolar.doCancelDem" dem_url = "scolar.do_cancel_dem"
# Note: seul un etudiant inscrit (I) peut devenir défaillant. # Note: seul un etudiant inscrit (I) peut devenir défaillant.
if ins["etat"] != sco_codes_parcours.DEF: if ins["etat"] != sco_codes_parcours.DEF:
def_title = "Déclarer défaillance" def_title = "Déclarer défaillance"
def_url = "scolar.formDef" def_url = "scolar.form_def"
elif ins["etat"] == sco_codes_parcours.DEF: elif ins["etat"] == sco_codes_parcours.DEF:
def_title = "Annuler la défaillance" def_title = "Annuler la défaillance"
def_url = "scolar.doCancelDef" def_url = "scolar.do_cancel_def"
def_enabled = ( def_enabled = (
(ins["etat"] != "D") (ins["etat"] != "D")
and authuser.has_permission(Permission.ScoEtudInscrit) and authuser.has_permission(Permission.ScoEtudInscrit)
@ -230,7 +230,7 @@ def ficheEtud(etudid=None):
info["last_formsemestre_id"] = "" info["last_formsemestre_id"] = ""
sem_info = {} sem_info = {}
for sem in info["sems"]: for sem in info["sems"]:
if sem["ins"]["etat"] != "I": if sem["ins"]["etat"] != scu.INSCRIT:
descr, _ = etud_descr_situation_semestre( descr, _ = etud_descr_situation_semestre(
etudid, etudid,
sem["formsemestre_id"], sem["formsemestre_id"],
@ -554,7 +554,7 @@ def menus_etud(etudid):
}, },
{ {
"title": "Changer la photo", "title": "Changer la photo",
"endpoint": "scolar.formChangePhoto", "endpoint": "scolar.form_change_photo",
"args": {"etudid": etud["etudid"]}, "args": {"etudid": etud["etudid"]},
"enabled": authuser.has_permission(Permission.ScoEtudChangeAdr), "enabled": authuser.has_permission(Permission.ScoEtudChangeAdr),
}, },

View File

@ -115,7 +115,7 @@ def etud_get_poursuite_info(sem, etud):
code_semestre_validant(dec["code"]) code_semestre_validant(dec["code"])
or code_semestre_attente(dec["code"]) or code_semestre_attente(dec["code"])
) )
and nt.get_etud_etat(etudid) == "I" and nt.get_etud_etat(etudid) == scu.INSCRIT
): ):
d = [ d = [
("moy", scu.fmt_note(nt.get_etud_moy_gen(etudid))), ("moy", scu.fmt_note(nt.get_etud_moy_gen(etudid))),

View File

@ -350,7 +350,9 @@ def dict_pvjury(
if Se.prev and Se.prev_decision: if Se.prev and Se.prev_decision:
d["prev_decision_sem"] = Se.prev_decision d["prev_decision_sem"] = Se.prev_decision
d["prev_code"] = Se.prev_decision["code"] d["prev_code"] = Se.prev_decision["code"]
d["prev_code_descr"] = _descr_decision_sem("I", Se.prev_decision) d["prev_code_descr"] = _descr_decision_sem(
scu.INSCRIT, Se.prev_decision
)
d["prev"] = Se.prev d["prev"] = Se.prev
has_prev = True has_prev = True
else: else:

View File

@ -1315,7 +1315,7 @@ def graph_parcours(
s["semestre_id"] == nt.parcours.NB_SEM s["semestre_id"] == nt.parcours.NB_SEM
and dec and dec
and code_semestre_validant(dec["code"]) and code_semestre_validant(dec["code"])
and nt.get_etud_etat(etudid) == "I" and nt.get_etud_etat(etudid) == scu.INSCRIT
): ):
# cas particulier du diplome puis poursuite etude # cas particulier du diplome puis poursuite etude
edges[ edges[
@ -1360,7 +1360,7 @@ def graph_parcours(
if ( if (
dec dec
and code_semestre_validant(dec["code"]) and code_semestre_validant(dec["code"])
and nt.get_etud_etat(etudid) == "I" and nt.get_etud_etat(etudid) == scu.INSCRIT
): ):
nid = sem_node_name(s, "_dipl_") nid = sem_node_name(s, "_dipl_")
edges[(sem_node_name(s), nid)].add(etudid) edges[(sem_node_name(s), nid)].add(etudid)

View File

@ -658,7 +658,7 @@ def do_import_etuds_from_portal(sem, a_importer, etudsapo_ident):
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
sem["formsemestre_id"], sem["formsemestre_id"],
args["etudid"], args["etudid"],
etat="I", etat=scu.INSCRIT,
etape=args["etape"], etape=args["etape"],
method="synchro_apogee", method="synchro_apogee",
) )

View File

@ -145,7 +145,9 @@ def pdf_trombino_tours(
for group_id in groups_infos.group_ids: for group_id in groups_infos.group_ids:
if group_id != "None": if group_id != "None":
members, _, group_tit, sem, _ = sco_groups.get_group_infos(group_id, "I") members, _, group_tit, sem, _ = sco_groups.get_group_infos(
group_id, scu.INSCRIT
)
groups += " %s" % group_tit groups += " %s" % group_tit
L = [] L = []
currow = [] currow = []
@ -391,7 +393,7 @@ def pdf_feuille_releve_absences(
) )
for group_id in groups_infos.group_ids: for group_id in groups_infos.group_ids:
members, _, group_tit, _, _ = sco_groups.get_group_infos(group_id, "I") members, _, group_tit, _, _ = sco_groups.get_group_infos(group_id, scu.INSCRIT)
L = [] L = []
currow = [ currow = [

View File

@ -1034,6 +1034,10 @@ div.sco_help {
background-color: rgb(200, 200, 220); background-color: rgb(200, 200, 220);
} }
div.vertical_spacing_but {
margin-top: 12px;
}
span.wtf-field ul.errors li { span.wtf-field ul.errors li {
color: red; color: red;
} }

View File

@ -52,12 +52,11 @@ from app.decorators import (
admin_required, admin_required,
login_required, login_required,
) )
from app.models import formsemestre
from app.models.etudiants import Identite from app.models.etudiants import Identite
from app.models.etudiants import make_etud_args from app.models.etudiants import make_etud_args
from app.models.events import ScolarNews from app.models.events import ScolarNews, Scolog
from app.models.formsemestre import FormSemestre from app.models.formsemestre import FormSemestre
from app.models.validations import ScolarEvent
from app.views import scolar_bp as bp from app.views import scolar_bp as bp
from app.views import ScoData from app.views import ScoData
@ -972,11 +971,11 @@ def etud_photo_orig_page(etudid=None):
return "\n".join(H) return "\n".join(H)
@bp.route("/formChangePhoto", methods=["GET", "POST"]) @bp.route("/form_change_photo", methods=["GET", "POST"])
@scodoc @scodoc
@permission_required(Permission.ScoEtudChangeAdr) @permission_required(Permission.ScoEtudChangeAdr)
@scodoc7func @scodoc7func
def formChangePhoto(etudid=None): def form_change_photo(etudid=None):
"""Formulaire changement photo étudiant""" """Formulaire changement photo étudiant"""
etud = sco_etud.get_etud_info(filled=True)[0] etud = sco_etud.get_etud_info(filled=True)[0]
if sco_photos.etud_photo_is_local(etud): if sco_photos.etud_photo_is_local(etud):
@ -1014,7 +1013,7 @@ def formChangePhoto(etudid=None):
return ( return (
"\n".join(H) "\n".join(H)
+ tf[1] + tf[1]
+ '<p><a class="stdlink" href="formSuppressPhoto?etudid=%s">Supprimer cette photo</a></p>' + '<p><a class="stdlink" href="form_suppress_photo?etudid=%s">Supprimer cette photo</a></p>'
% etudid % etudid
+ html_sco_header.sco_footer() + html_sco_header.sco_footer()
) )
@ -1032,13 +1031,15 @@ def formChangePhoto(etudid=None):
return "\n".join(H) + html_sco_header.sco_footer() return "\n".join(H) + html_sco_header.sco_footer()
@bp.route("/formSuppressPhoto", methods=["POST", "GET"]) @bp.route("/form_suppress_photo", methods=["POST", "GET"])
@scodoc @scodoc
@permission_required(Permission.ScoEtudChangeAdr) @permission_required(Permission.ScoEtudChangeAdr)
@scodoc7func @scodoc7func
def formSuppressPhoto(etudid=None, dialog_confirmed=False): def form_suppress_photo(etudid=None, dialog_confirmed=False):
"""Formulaire suppression photo étudiant""" """Formulaire suppression photo étudiant"""
etud = Identite.query.get_or_404(etudid) etud: Identite = Identite.query.filter_by(
id=etudid, dept_id=g.scodoc_dept_id
).first_or_404()
if not dialog_confirmed: if not dialog_confirmed:
return scu.confirm_dialog( return scu.confirm_dialog(
f"<p>Confirmer la suppression de la photo de {etud.nom_disp()} ?</p>", f"<p>Confirmer la suppression de la photo de {etud.nom_disp()} ?</p>",
@ -1057,99 +1058,91 @@ def formSuppressPhoto(etudid=None, dialog_confirmed=False):
# #
@bp.route("/formDem") @bp.route("/form_dem")
@scodoc @scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func @scodoc7func
def formDem(etudid, formsemestre_id): def form_dem(etudid, formsemestre_id):
"Formulaire Démission Etudiant" "Formulaire Démission Etudiant"
return _formDem_of_Def( return _form_dem_of_def(
etudid, etudid,
formsemestre_id, formsemestre_id,
operation_name="Démission", operation_name="Démission",
operation_method="doDemEtudiant", operation_method="do_dem_etudiant",
) )
@bp.route("/formDef") @bp.route("/form_def")
@scodoc @scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func @scodoc7func
def formDef(etudid, formsemestre_id): def form_def(etudid, formsemestre_id):
"Formulaire Défaillance Etudiant" "Formulaire Défaillance Etudiant"
return _formDem_of_Def( return _form_dem_of_def(
etudid, etudid,
formsemestre_id, formsemestre_id,
operation_name="Défaillance", operation_name="Défaillance",
operation_method="doDefEtudiant", operation_method="do_def_etudiant",
) )
def _formDem_of_Def( def _form_dem_of_def(
etudid, etudid: int,
formsemestre_id, formsemestre_id: int,
operation_name="", operation_name: str = "",
operation_method="", operation_method: str = "",
): ):
"Formulaire démission ou défaillance Etudiant" "Formulaire démission ou défaillance Etudiant"
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0] etud: Identite = Identite.query.filter_by(
sem = sco_formsemestre.get_formsemestre(formsemestre_id) id=etudid, dept_id=g.scodoc_dept_id
if not sem["etat"]: ).first_or_404()
formsemestre: FormSemestre = FormSemestre.query.filter_by(
id=formsemestre_id, dept_id=g.scodoc_dept_id
).first_or_404()
if not formsemestre.etat:
raise ScoValueError("Modification impossible: semestre verrouille") raise ScoValueError("Modification impossible: semestre verrouille")
nowdmy = time.strftime("%d/%m/%Y")
etud["formsemestre_id"] = formsemestre_id
etud["semtitre"] = sem["titremois"]
etud["nowdmy"] = time.strftime("%d/%m/%Y")
etud["operation_name"] = operation_name
# #
header = html_sco_header.sco_header( header = html_sco_header.sco_header(
page_title="%(operation_name)s de %(nomprenom)s (du semestre %(semtitre)s)" page_title=f"""{operation_name} de {etud.nomprenom} (du semestre {formsemestre.titre_mois()})"""
% etud,
) )
H = [ return f"""
'<h2><font color="#FF0000">%(operation_name)s de</font> %(nomprenom)s (semestre %(semtitre)s)</h2><p>' {header}
% etud <h2><font color="#FF0000">{operation_name} de</font> {etud.nomprenom} ({formsemestre.titre_mois()})</h2>
]
H.append( <form action="{operation_method}" method="get">
"""<form action="%s" method="get"> <div><b>Date de la {operation_name.lower()} (J/M/AAAA):&nbsp;</b>
<b>Date de la %s (J/M/AAAA):&nbsp;</b> <input type="text" name="event_date" width=20 value="{nowdmy}">
</div>
<input type="hidden" name="etudid" value="{etudid}">
<input type="hidden" name="formsemestre_id" value="{formsemestre_id}">
<div class="vertical_spacing_but"><input type="submit" value="Confirmer"></div>
</form>
{html_sco_header.sco_footer()}
""" """
% (operation_method, operation_name.lower())
)
H.append(
"""
<input type="text" name="event_date" width=20 value="%(nowdmy)s">
<input type="hidden" name="etudid" value="%(etudid)s">
<input type="hidden" name="formsemestre_id" value="%(formsemestre_id)s">
<p>
<input type="submit" value="Confirmer">
</form>"""
% etud
)
return header + "\n".join(H) + html_sco_header.sco_footer()
@bp.route("/doDemEtudiant") @bp.route("/do_dem_etudiant")
@scodoc @scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func @scodoc7func
def doDemEtudiant(etudid, formsemestre_id, event_date=None): def do_dem_etudiant(etudid, formsemestre_id, event_date=None):
"Déclare la démission d'un etudiant dans le semestre" "Déclare la démission d'un etudiant dans le semestre"
return _do_dem_or_def_etud( return _do_dem_or_def_etud(
etudid, etudid,
formsemestre_id, formsemestre_id,
event_date=event_date, event_date=event_date,
etat_new="D", etat_new=scu.DEMISSION,
operation_method="demEtudiant", operation_method="dem_etudiant",
event_type="DEMISSION", event_type="DEMISSION",
) )
@bp.route("/doDefEtudiant") @bp.route("/do_def_etudiant")
@scodoc @scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func @scodoc7func
def doDefEtudiant(etudid, formsemestre_id, event_date=None): def do_def_etudiant(etudid, formsemestre_id, event_date=None):
"Déclare la défaillance d'un etudiant dans le semestre" "Déclare la défaillance d'un etudiant dans le semestre"
return _do_dem_or_def_etud( return _do_dem_or_def_etud(
etudid, etudid,
@ -1165,7 +1158,7 @@ def _do_dem_or_def_etud(
etudid, etudid,
formsemestre_id, formsemestre_id,
event_date=None, event_date=None,
etat_new="D", # 'D' or DEF etat_new=scu.DEMISSION, # DEMISSION or DEF
operation_method="demEtudiant", operation_method="demEtudiant",
event_type="DEMISSION", event_type="DEMISSION",
redirect=True, redirect=True,
@ -1175,7 +1168,7 @@ def _do_dem_or_def_etud(
etudid, etudid,
formsemestre_id, formsemestre_id,
event_date=event_date, event_date=event_date,
etat_new=etat_new, # 'D' or DEF etat_new=etat_new, # DEMISSION or DEF
operation_method=operation_method, operation_method=operation_method,
event_type=event_type, event_type=event_type,
) )
@ -1185,11 +1178,11 @@ def _do_dem_or_def_etud(
) )
@bp.route("/doCancelDem", methods=["GET", "POST"]) @bp.route("/do_cancel_dem", methods=["GET", "POST"])
@scodoc @scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func @scodoc7func
def doCancelDem(etudid, formsemestre_id, dialog_confirmed=False, args=None): def do_cancel_dem(etudid, formsemestre_id, dialog_confirmed=False, args=None):
"Annule une démission" "Annule une démission"
return _do_cancel_dem_or_def( return _do_cancel_dem_or_def(
etudid, etudid,
@ -1197,18 +1190,18 @@ def doCancelDem(etudid, formsemestre_id, dialog_confirmed=False, args=None):
dialog_confirmed=dialog_confirmed, dialog_confirmed=dialog_confirmed,
args=args, args=args,
operation_name="démission", operation_name="démission",
etat_current="D", etat_current=scu.DEMISSION,
etat_new="I", etat_new=scu.INSCRIT,
operation_method="cancelDem", operation_method="cancelDem",
event_type="DEMISSION", event_type="DEMISSION",
) )
@bp.route("/doCancelDef", methods=["GET", "POST"]) @bp.route("/do_cancel_def", methods=["GET", "POST"])
@scodoc @scodoc
@permission_required(Permission.ScoEtudInscrit) @permission_required(Permission.ScoEtudInscrit)
@scodoc7func @scodoc7func
def doCancelDef(etudid, formsemestre_id, dialog_confirmed=False, args=None): def do_cancel_def(etudid, formsemestre_id, dialog_confirmed=False, args=None):
"Annule la défaillance de l'étudiant" "Annule la défaillance de l'étudiant"
return _do_cancel_dem_or_def( return _do_cancel_dem_or_def(
etudid, etudid,
@ -1217,8 +1210,8 @@ def doCancelDef(etudid, formsemestre_id, dialog_confirmed=False, args=None):
args=args, args=args,
operation_name="défaillance", operation_name="défaillance",
etat_current=sco_codes_parcours.DEF, etat_current=sco_codes_parcours.DEF,
etat_new="I", etat_new=scu.INSCRIT,
operation_method="cancelDef", operation_method="cancel_def",
event_type="DEFAILLANCE", event_type="DEFAILLANCE",
) )
@ -1229,30 +1222,30 @@ def _do_cancel_dem_or_def(
dialog_confirmed=False, dialog_confirmed=False,
args=None, args=None,
operation_name="", # "démission" ou "défaillance" operation_name="", # "démission" ou "défaillance"
etat_current="D", etat_current=scu.DEMISSION,
etat_new="I", etat_new=scu.INSCRIT,
operation_method="cancelDem", operation_method="cancel_dem",
event_type="DEMISSION", event_type="DEMISSION",
): ):
"Annule une demission ou une défaillance" "Annule une démission ou une défaillance"
etud: Identite = Identite.query.filter_by(
id=etudid, dept_id=g.scodoc_dept_id
).first_or_404()
formsemestre: FormSemestre = FormSemestre.query.filter_by(
id=formsemestre_id, dept_id=g.scodoc_dept_id
).first_or_404()
# check lock # check lock
sem = sco_formsemestre.get_formsemestre(formsemestre_id) if not formsemestre.etat:
if not sem["etat"]:
raise ScoValueError("Modification impossible: semestre verrouille") raise ScoValueError("Modification impossible: semestre verrouille")
# verif # verif
info = sco_etud.get_etud_info(etudid, filled=True)[0] if formsemestre_id not in (inscr.formsemestre_id for inscr in etud.inscriptions()):
ok = False raise ScoValueError("étudiant non inscrit dans ce semestre !")
for i in info["ins"]: if etud.inscription_etat(formsemestre_id) != etat_current:
if i["formsemestre_id"] == formsemestre_id: raise ScoValueError(f"etudiant non {operation_name} !")
if i["etat"] != etat_current:
raise ScoValueError("etudiant non %s !" % operation_name)
ok = True
break
if not ok:
raise ScoValueError("etudiant non inscrit ???")
if not dialog_confirmed: if not dialog_confirmed:
return scu.confirm_dialog( return scu.confirm_dialog(
"<p>Confirmer l'annulation de la %s ?</p>" % operation_name, f"<p>Confirmer l'annulation de la {operation_name} ?</p>",
dest_url="", dest_url="",
cancel_url=url_for( cancel_url=url_for(
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid
@ -1260,25 +1253,22 @@ def _do_cancel_dem_or_def(
parameters={"etudid": etudid, "formsemestre_id": formsemestre_id}, parameters={"etudid": etudid, "formsemestre_id": formsemestre_id},
) )
# #
ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_list( inscr = next(
{"etudid": etudid, "formsemestre_id": formsemestre_id} inscr
)[0] for inscr in etud.inscriptions()
if ins["etat"] != etat_current: if inscr.formsemestre_id == formsemestre_id
raise ScoException("etudiant non %s !!!" % etat_current) # obviously a bug
ins["etat"] = etat_new
cnx = ndb.GetDBConnexion()
sco_formsemestre_inscriptions.do_formsemestre_inscription_edit(
args=ins, formsemestre_id=formsemestre_id
) )
logdb(cnx, method=operation_method, etudid=etudid) inscr.etat = etat_new
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) db.session.add(inscr)
cursor.execute( Scolog.logdb(method=operation_method, etudid=etudid)
"delete from scolar_events where etudid=%(etudid)s and formsemestre_id=%(formsemestre_id)s and event_type='" # Efface les évènements
+ event_type for event in ScolarEvent.query.filter_by(
+ "'", etudid=etudid, formsemestre_id=formsemestre_id, event_type=event_type
{"etudid": etudid, "formsemestre_id": formsemestre_id}, ):
) db.session.delete(event)
cnx.commit()
db.session.commit()
flash(f"{operation_name} annulée.")
return flask.redirect( return flask.redirect(
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
) )