préparatifs/refactoring

This commit is contained in:
Emmanuel Viennet 2021-12-04 21:04:09 +01:00
parent c455f6261f
commit b1bc8b3f41
11 changed files with 182 additions and 67 deletions

View File

@ -49,6 +49,32 @@ class Identite(db.Model):
def __repr__(self): def __repr__(self):
return f"<Etud {self.id} {self.nom} {self.prenom}>" return f"<Etud {self.id} {self.nom} {self.prenom}>"
def civilite_str(self):
"""returns 'M.' ou 'Mme' ou '' (pour le genre neutre,
personnes ne souhaitant pas d'affichage).
"""
return {"M": "M.", "F": "Mme", "X": ""}[self.civilite]
def nom_disp(self):
"nom à afficher"
if self.nom_usuel:
return (
(self.nom_usuel + " (" + self.nom + ")") if self.nom else self.nom_usuel
)
else:
return self.nom
def inscription_courante(self):
"""La première inscription à un formsemestre _actuellement_ en cours.
None s'il n'y en a pas (ou plus, ou pas encore).
"""
r = [
ins
for ins in self.formsemestre_inscriptions
if ins.formsemestre.est_courant()
]
return r[0] if r else None
class Adresse(db.Model): class Adresse(db.Model):
"""Adresse d'un étudiant """Adresse d'un étudiant

View File

@ -241,7 +241,7 @@ class Module(db.Model):
def is_apc(self): def is_apc(self):
"True si module SAÉ ou Ressource" "True si module SAÉ ou Ressource"
return scu.ModuleType(self.module_type) in { return self.module_type and scu.ModuleType(self.module_type) in {
scu.ModuleType.RESSOURCE, scu.ModuleType.RESSOURCE,
scu.ModuleType.SAE, scu.ModuleType.SAE,
} }

View File

@ -2,6 +2,7 @@
"""ScoDoc models: formsemestre """ScoDoc models: formsemestre
""" """
import datetime
from typing import Any from typing import Any
import flask_sqlalchemy import flask_sqlalchemy
@ -13,11 +14,14 @@ from app.models import CODE_STR_LEN
from app.models import UniteEns from app.models import UniteEns
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
from app.scodoc import sco_evaluation_db from app.scodoc import sco_evaluation_db
from app.models.formations import UniteEns, Module from app.models.formations import UniteEns, Module
from app.models.moduleimpls import ModuleImpl from app.models.moduleimpls import ModuleImpl
from app.models.etudiants import Identite from app.models.etudiants import Identite
from app.scodoc import sco_codes_parcours from app.scodoc import sco_codes_parcours
from app.scodoc import sco_preferences
from app.scodoc.sco_vdi import ApoEtapeVDI
class FormSemestre(db.Model): class FormSemestre(db.Model):
@ -40,7 +44,7 @@ class FormSemestre(db.Model):
) # False si verrouillé ) # False si verrouillé
modalite = db.Column( modalite = db.Column(
db.String(SHORT_STR_LEN), db.ForeignKey("notes_form_modalites.modalite") db.String(SHORT_STR_LEN), db.ForeignKey("notes_form_modalites.modalite")
) ) # "FI", "FAP", "FC", ...
# gestion compensation sem DUT: # gestion compensation sem DUT:
gestion_compensation = db.Column( gestion_compensation = db.Column(
db.Boolean(), nullable=False, default=False, server_default="false" db.Boolean(), nullable=False, default=False, server_default="false"
@ -89,7 +93,12 @@ class FormSemestre(db.Model):
viewonly=True, viewonly=True,
lazy="dynamic", lazy="dynamic",
) )
responsables = db.relationship(
"User",
secondary="notes_formsemestre_responsables",
lazy=True,
backref=db.backref("formsemestres", lazy=True),
)
# Ancien id ScoDoc7 pour les migrations de bases anciennes # Ancien id ScoDoc7 pour les migrations de bases anciennes
# ne pas utiliser après migrate_scodoc7_dept_archives # ne pas utiliser après migrate_scodoc7_dept_archives
scodoc7_id = db.Column(db.Text(), nullable=True) scodoc7_id = db.Column(db.Text(), nullable=True)
@ -99,6 +108,18 @@ class FormSemestre(db.Model):
if self.modalite is None: if self.modalite is None:
self.modalite = FormationModalite.DEFAULT_MODALITE self.modalite = FormationModalite.DEFAULT_MODALITE
def to_dict(self):
d = dict(self.__dict__)
d.pop("_sa_instance_state", None)
# ScoDoc7 output_formators: (backward compat)
d["formsemestre_id"] = self.id
d["date_debut"] = (
self.date_debut.strftime("%d/%m/%Y") if self.date_debut else ""
)
d["date_fin"] = self.date_fin.strftime("%d/%m/%Y") if self.date_fin else ""
d["responsables"] = [u.id for u in self.responsables]
return d
def query_ues(self, with_sport=False) -> flask_sqlalchemy.BaseQuery: def query_ues(self, with_sport=False) -> flask_sqlalchemy.BaseQuery:
"""UE des modules de ce semestre. """UE des modules de ce semestre.
- Formations classiques: les UEs auxquelles appartiennent - Formations classiques: les UEs auxquelles appartiennent
@ -120,6 +141,76 @@ class FormSemestre(db.Model):
sem_ues = sem_ues.filter(UniteEns.type != sco_codes_parcours.UE_SPORT) sem_ues = sem_ues.filter(UniteEns.type != sco_codes_parcours.UE_SPORT)
return sem_ues return sem_ues
def est_courant(self) -> bool:
"""Vrai si la date actuelle (now) est dans le semestre
(les dates de début et fin sont incluses)
"""
today = datetime.date.today()
return (self.date_debut <= today) and (today <= self.date_fin)
def est_decale(self):
"""Vrai si semestre "décalé"
c'est à dire semestres impairs commençant entre janvier et juin
et les pairs entre juillet et decembre
"""
if self.semestre_id <= 0:
return False # formations sans semestres
return (self.semestre_id % 2 and self.date_debut.month <= 6) or (
not self.semestre_id % 2 and self.date_debut.month > 6
)
def etapes_apo_str(self) -> str:
"""Chaine décrivant les étapes de ce semestre
ex: "V1RT, V1RT3, V1RT4"
"""
if not self.etapes:
return ""
return ", ".join([str(x.etape_apo) for x in self.etapes])
def responsables_str(self, abbrev_prenom=True) -> str:
"""chaîne "J. Dupond, X. Martin"
ou "Jacques Dupond, Xavier Martin"
"""
if not self.responsables:
return ""
if abbrev_prenom:
return ", ".join([u.get_prenomnom() for u in self.responsables])
else:
return ", ".join([u.get_nomcomplet() for u in self.responsables])
def session_id(self) -> str:
"""identifiant externe de semestre de formation
Exemple: RT-DUT-FI-S1-ANNEE
DEPT-TYPE-MODALITE+-S?|SPECIALITE
TYPE=DUT|LP*|M*
MODALITE=FC|FI|FA (si plusieurs, en inverse alpha)
SPECIALITE=[A-Z]+ EON,ASSUR, ... (si pas Sn ou SnD)
ANNEE=annee universitaire de debut (exemple: un S2 de 2013-2014 sera S2-2013)
"""
imputation_dept = sco_preferences.get_preference("ImputationDept", self.id)
if not imputation_dept:
imputation_dept = sco_preferences.get_preference("DeptName")
imputation_dept = imputation_dept.upper()
parcours_name = self.formation.get_parcours().NAME
modalite = self.modalite
# exception pour code Apprentissage:
modalite = (modalite or "").replace("FAP", "FA").replace("APP", "FA")
if self.semestre_id > 0:
decale = "D" if self.est_decale() else ""
semestre_id = f"S{self.semestre_id}{decale}"
else:
semestre_id = self.formation.code_specialite or ""
annee_sco = str(
scu.annee_scolaire_debut(self.date_debut.year, self.date_debut.month)
)
return scu.sanitize_string(
"-".join((imputation_dept, parcours_name, modalite, semestre_id, annee_sco))
)
# Association id des utilisateurs responsables (aka directeurs des etudes) du semestre # Association id des utilisateurs responsables (aka directeurs des etudes) du semestre
notes_formsemestre_responsables = db.Table( notes_formsemestre_responsables = db.Table(
@ -144,6 +235,12 @@ class FormsemestreEtape(db.Model):
) )
etape_apo = db.Column(db.String(APO_CODE_STR_LEN)) etape_apo = db.Column(db.String(APO_CODE_STR_LEN))
def __repr__(self):
return f"<Etape {self.id} apo={self.etape_apo}>"
def as_apovdi(self):
return ApoEtapeVDI(self.etape_apo)
class FormationModalite(db.Model): class FormationModalite(db.Model):
"""Modalités de formation, utilisées pour la présentation """Modalités de formation, utilisées pour la présentation

View File

@ -1028,20 +1028,26 @@ def get_abs_count(etudid, sem):
tuple (nb abs non justifiées, nb abs justifiées) tuple (nb abs non justifiées, nb abs justifiées)
Utilise un cache. Utilise un cache.
""" """
date_debut = sem["date_debut_iso"] return get_abs_count_in_interval(etudid, sem["date_debut_iso"], sem["date_fin_iso"])
date_fin = sem["date_fin_iso"]
key = str(etudid) + "_" + date_debut + "_" + date_fin
def get_abs_count_in_interval(etudid, date_debut_iso, date_fin_iso):
"""Les comptes d'absences de cet étudiant entre ces deux dates, incluses:
tuple (nb abs non justifiées, nb abs justifiées)
Utilise un cache.
"""
key = str(etudid) + "_" + date_debut_iso + "_" + date_fin_iso
r = sco_cache.AbsSemEtudCache.get(key) r = sco_cache.AbsSemEtudCache.get(key)
if not r: if not r:
nb_abs = count_abs( # was CountAbs XXX nb_abs = count_abs(
etudid=etudid, etudid=etudid,
debut=date_debut, debut=date_debut_iso,
fin=date_fin, fin=date_fin_iso,
) )
nb_abs_just = count_abs_just( # XXX was CountAbsJust nb_abs_just = count_abs_just(
etudid=etudid, etudid=etudid,
debut=date_debut, debut=date_debut_iso,
fin=date_fin, fin=date_fin_iso,
) )
r = (nb_abs, nb_abs_just) r = (nb_abs, nb_abs_just)
ans = sco_cache.AbsSemEtudCache.set(key, r) ans = sco_cache.AbsSemEtudCache.set(key, r)

View File

@ -584,7 +584,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
H.append( H.append(
f""" f"""
<ul> <ul>
<li>{descr_refcomp} <a class="stdlink" href="{url_for('notes.refcomp_assoc', <li>{descr_refcomp} <a class="stdlink" href="{url_for('notes.refcomp_assoc_formation',
scodoc_dept=g.scodoc_dept, formation_id=formation_id) scodoc_dept=g.scodoc_dept, formation_id=formation_id)
}">{msg_refcomp}</a> }">{msg_refcomp}</a>
</li> </li>

View File

@ -47,36 +47,6 @@ from app.scodoc import sco_preferences
from app.scodoc.scolog import logdb from app.scodoc.scolog import logdb
from app.scodoc.TrivialFormulator import TrivialFormulator from app.scodoc.TrivialFormulator import TrivialFormulator
MONTH_NAMES_ABBREV = [
"Jan ",
"Fév ",
"Mars",
"Avr ",
"Mai ",
"Juin",
"Jul ",
"Août",
"Sept",
"Oct ",
"Nov ",
"Déc ",
]
MONTH_NAMES = [
"janvier",
"février",
"mars",
"avril",
"mai",
"juin",
"juillet",
"août",
"septembre",
"octobre",
"novembre",
"décembre",
]
def format_etud_ident(etud): def format_etud_ident(etud):
"""Format identite de l'étudiant (modifié en place) """Format identite de l'étudiant (modifié en place)

View File

@ -194,7 +194,7 @@ def _formsemestre_enrich(sem):
sem["titreannee"] += "-" + annee_fin sem["titreannee"] += "-" + annee_fin
sem["annee"] += "-" + annee_fin sem["annee"] += "-" + annee_fin
# et les dates sous la forme "oct 2007 - fev 2008" # et les dates sous la forme "oct 2007 - fev 2008"
months = sco_etud.MONTH_NAMES_ABBREV months = scu.MONTH_NAMES_ABBREV
if mois_debut: if mois_debut:
mois_debut = months[int(mois_debut) - 1] mois_debut = months[int(mois_debut) - 1]
if mois_fin: if mois_fin:
@ -470,7 +470,7 @@ def sem_une_annee(sem):
return debut == fin return debut == fin
def sem_est_courant(sem): def sem_est_courant(sem): # -> FormSemestre.est_courant
"""Vrai si la date actuelle (now) est dans le semestre (les dates de début et fin sont incluses)""" """Vrai si la date actuelle (now) est dans le semestre (les dates de début et fin sont incluses)"""
now = time.strftime("%Y-%m-%d") now = time.strftime("%Y-%m-%d")
debut = ndb.DateDMYtoISO(sem["date_debut"]) debut = ndb.DateDMYtoISO(sem["date_debut"])

View File

@ -1621,28 +1621,14 @@ def formsemestre_edit_uecoefs(formsemestre_id, err_ue_id=None):
# ----- identification externe des sessions (pour SOJA et autres logiciels) # ----- identification externe des sessions (pour SOJA et autres logiciels)
def get_formsemestre_session_id(sem, F, parcours): def get_formsemestre_session_id(sem, F, parcours):
"""Identifiant de session pour ce semestre """Identifiant de session pour ce semestre
Exemple: RT-DUT-FI-S1-ANNEE Obsolete: vooir FormSemestre.session_id() #sco7
DEPT-TYPE-MODALITE+-S?|SPECIALITE
TYPE=DUT|LP*|M*
MODALITE=FC|FI|FA (si plusieurs, en inverse alpha)
SPECIALITE=[A-Z]+ EON,ASSUR, ... (si pas Sn ou SnD)
ANNEE=annee universitaire de debut (exemple: un S2 de 2013-2014 sera S2-2013)
""" """
# sem = sco_formsemestre.get_formsemestre( formsemestre_id) imputation_dept = sco_preferences.get_preference(
# F = sco_formations.formation_list( args={ 'formation_id' : sem['formation_id'] } )[0]
# parcours = sco_codes_parcours.get_parcours_from_code(F['type_parcours'])
ImputationDept = sco_preferences.get_preference(
"ImputationDept", sem["formsemestre_id"] "ImputationDept", sem["formsemestre_id"]
) )
if not ImputationDept: if not imputation_dept:
ImputationDept = sco_preferences.get_preference("DeptName") imputation_dept = sco_preferences.get_preference("DeptName")
ImputationDept = ImputationDept.upper() imputation_dept = imputation_dept.upper()
parcours_type = parcours.NAME parcours_type = parcours.NAME
modalite = sem["modalite"] modalite = sem["modalite"]
modalite = ( modalite = (
@ -1656,5 +1642,5 @@ def get_formsemestre_session_id(sem, F, parcours):
annee_sco = str(scu.annee_scolaire_debut(sem["annee_debut"], sem["mois_debut_ord"])) annee_sco = str(scu.annee_scolaire_debut(sem["annee_debut"], sem["mois_debut_ord"]))
return scu.sanitize_string( return scu.sanitize_string(
"-".join((ImputationDept, parcours_type, modalite, semestre_id, annee_sco)) "-".join((imputation_dept, parcours_type, modalite, semestre_id, annee_sco))
) )

View File

@ -151,7 +151,7 @@ def scolar_news_summary(n=5):
n[k] = _scolar_news_editor.output_formators[k](n[k]) n[k] = _scolar_news_editor.output_formators[k](n[k])
# date resumee # date resumee
j, m = n["date"].split("/")[:2] j, m = n["date"].split("/")[:2]
mois = sco_etud.MONTH_NAMES_ABBREV[int(m) - 1] mois = scu.MONTH_NAMES_ABBREV[int(m) - 1]
n["formatted_date"] = "%s %s %s" % (j, mois, n["hm"]) n["formatted_date"] = "%s %s %s" % (j, mois, n["hm"])
# indication semestre si ajout notes: # indication semestre si ajout notes:
infos = _get_formsemestre_infos_from_news(n) infos = _get_formsemestre_infos_from_news(n)

View File

@ -212,7 +212,7 @@ def placement_eval_selectetuds(evaluation_id):
) )
return runner.exec_placement() # calcul et generation du fichier return runner.exec_placement() # calcul et generation du fichier
htmls = [ htmls = [
html_sco_header.sco_header(init_jquery_ui=True), html_sco_header.sco_header(),
sco_evaluations.evaluation_describe(evaluation_id=evaluation_id), sco_evaluations.evaluation_describe(evaluation_id=evaluation_id),
"<h3>Placement et émargement des étudiants</h3>", "<h3>Placement et émargement des étudiants</h3>",
render_template("scodoc/forms/placement.html", form=form), render_template("scodoc/forms/placement.html", form=form),

View File

@ -127,6 +127,36 @@ EVALUATION_NORMALE = 0
EVALUATION_RATTRAPAGE = 1 EVALUATION_RATTRAPAGE = 1
EVALUATION_SESSION2 = 2 EVALUATION_SESSION2 = 2
MONTH_NAMES_ABBREV = (
"Jan ",
"Fév ",
"Mars",
"Avr ",
"Mai ",
"Juin",
"Jul ",
"Août",
"Sept",
"Oct ",
"Nov ",
"Déc ",
)
MONTH_NAMES = (
"janvier",
"février",
"mars",
"avril",
"mai",
"juin",
"juillet",
"août",
"septembre",
"octobre",
"novembre",
"décembre",
)
def fmt_note(val, note_max=None, keep_numeric=False): def fmt_note(val, note_max=None, keep_numeric=False):
"""conversion note en str pour affichage dans tables HTML ou PDF. """conversion note en str pour affichage dans tables HTML ou PDF.