1
0
forked from ScoDoc/ScoDoc

Refactoring: cursus Classic/ECTS/BUT

This commit is contained in:
Emmanuel Viennet 2022-07-07 16:24:52 +02:00
parent 7c340c798a
commit 81e7914620
21 changed files with 312 additions and 228 deletions

56
app/but/cursus_but.py Normal file
View File

@ -0,0 +1,56 @@
##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""Cursus en BUT
Classe raccordant avec ScoDoc 7:
ScoDoc 7 utilisait sco_cursus_dut.SituationEtudCursus
Ce module définit une classe SituationEtudCursusBUT
avec la même interface.
"""
from typing import Union
from flask import g, url_for
from app import db
from app import log
from app.comp.res_but import ResultatsSemestreBUT
from app.comp import res_sem
from app.models import formsemestre
from app.models.but_refcomp import (
ApcAnneeParcours,
ApcCompetence,
ApcNiveau,
ApcParcours,
ApcParcoursNiveauCompetence,
)
from app.models import Scolog, ScolarAutorisationInscription
from app.models.but_validations import (
ApcValidationAnnee,
ApcValidationRCUE,
RegroupementCoherentUE,
)
from app.models.etudiants import Identite
from app.models.formations import Formation
from app.models.formsemestre import FormSemestre, FormSemestreInscription
from app.models.ues import UniteEns
from app.models.validations import ScolarFormSemestreValidation
from app.scodoc import sco_codes_parcours as sco_codes
from app.scodoc.sco_codes_parcours import RED, UE_STANDARD
from app.scodoc import sco_utils as scu
from app.scodoc.sco_exceptions import ScoException, ScoValueError
from app.scodoc import sco_cursus_dut
class SituationEtudCursusBUT(sco_cursus_dut.SituationEtudCursus):
def __init__(self, etud: dict, formsemestre_id: int, res: ResultatsSemestreBUT):
self.semestre_non_terminal = bool
self.formation

View File

@ -57,6 +57,11 @@ class ScolarFormSemestreValidation(db.Model):
def __repr__(self):
return f"{self.__class__.__name__}({self.formsemestre_id}, {self.etudid}, code={self.code}, ue={self.ue}, moy_ue={self.moy_ue})"
def to_dict(self) -> dict:
d = dict(self.__dict__)
d.pop("_sa_instance_state", None)
return d
class ScolarAutorisationInscription(db.Model):
"""Autorisation d'inscription dans un semestre"""
@ -78,6 +83,11 @@ class ScolarAutorisationInscription(db.Model):
db.ForeignKey("notes_formsemestre.id"),
)
def to_dict(self) -> dict:
d = dict(self.__dict__)
d.pop("_sa_instance_state", None)
return d
@classmethod
def autorise_etud(
cls,
@ -146,3 +156,8 @@ class ScolarEvent(db.Model):
db.Integer,
db.ForeignKey("notes_formsemestre.id"),
)
def to_dict(self) -> dict:
d = dict(self.__dict__)
d.pop("_sa_instance_state", None)
return d

View File

@ -54,22 +54,22 @@ from app.scodoc.sco_codes_parcours import (
ue_is_fondamentale,
ue_is_professionnelle,
)
from app.scodoc.sco_parcours_dut import formsemestre_get_etud_capitalisation
from app.scodoc import sco_cache
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_compute_moy
from app.scodoc import sco_cache
from app.scodoc.sco_cursus import formsemestre_get_etud_capitalisation
from app.scodoc import sco_cursus_dut
from app.scodoc import sco_edit_matiere
from app.scodoc import sco_edit_module
from app.scodoc import sco_edit_ue
from app.scodoc import sco_etud
from app.scodoc import sco_evaluations
from app.scodoc import sco_formations
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_groups
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_preferences
from app.scodoc import sco_etud
def comp_ranks(T):
@ -1175,7 +1175,7 @@ class NotesTable:
):
if not cnx:
cnx = ndb.GetDBConnexion()
sco_parcours_dut.do_formsemestre_validate_ue(
sco_cursus_dut.do_formsemestre_validate_ue(
cnx,
nt_cap,
ue_cap["formsemestre_id"],

View File

@ -112,8 +112,8 @@ from app.scodoc.sco_codes_parcours import (
NAR,
RAT,
)
from app.scodoc import sco_cursus
from app.scodoc import sco_formsemestre
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_etud
APO_PORTAL_ENCODING = (
@ -413,7 +413,7 @@ class ApoEtud(dict):
export_res_etape = self.export_res_etape
if (not export_res_etape) and cur_sem:
# exporte toujours le résultat de l'étape si l'étudiant est diplômé
Se = sco_parcours_dut.SituationEtudParcours(
Se = sco_cursus.get_situation_etud_cursus(
self.etud, cur_sem["formsemestre_id"]
)
export_res_etape = Se.all_other_validated()

View File

@ -231,7 +231,7 @@ def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=Fa
"""expire cache pour un semestre (ou tous si formsemestre_id non spécifié).
Si pdfonly, n'expire que les bulletins pdf cachés.
"""
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_cursus
if getattr(g, "defer_cache_invalidation", False):
g.sem_to_invalidate.add(formsemestre_id)
@ -252,7 +252,7 @@ def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=Fa
else:
formsemestre_ids = [
formsemestre_id
] + sco_parcours_dut.list_formsemestre_utilisateurs_uecap(formsemestre_id)
] + sco_cursus.list_formsemestre_utilisateurs_uecap(formsemestre_id)
log(f"----- invalidate_formsemestre: clearing {formsemestre_ids} -----")
if not pdfonly:

134
app/scodoc/sco_cursus.py Normal file
View File

@ -0,0 +1,134 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Emmanuel Viennet emmanuel.viennet@viennet.net
#
##############################################################################
"""Gestion des cursus (jurys suivant la formation)
"""
from app.but import cursus_but
from app.scodoc import sco_cursus_dut
from app.comp.res_compat import NotesTableCompat
from app.comp import res_sem
from app.models import FormSemestre
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formations
import app.scodoc.notesdb as ndb
# SituationEtudParcours -> get_situation_etud_cursus
def get_situation_etud_cursus(
etud: dict, formsemestre_id: int
) -> sco_cursus_dut.SituationEtudCursus:
"""renvoie une instance de SituationEtudCursus (ou sous-classe spécialisée)"""
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
if formsemestre.formation.is_apc():
return cursus_but.SituationEtudCursusBUT(etud, formsemestre_id, nt)
parcours = nt.parcours
if parcours.ECTS_ONLY:
return sco_cursus_dut.SituationEtudCursusECTS(etud, formsemestre_id, nt)
return sco_cursus_dut.SituationEtudCursusClassic(etud, formsemestre_id, nt)
def formsemestre_get_etud_capitalisation(
formation_id: int, semestre_idx: int, date_debut, etudid: int
) -> list[dict]:
"""Liste des UE capitalisées (ADM) correspondant au semestre sem et à l'étudiant.
Recherche dans les semestres de la même formation (code) avec le même
semestre_id et une date de début antérieure à celle du semestre mentionné.
Et aussi les UE externes validées.
Resultat: [ { 'formsemestre_id' :
'ue_id' : ue_id dans le semestre origine
'ue_code' :
'moy_ue' :
'event_date' :
'is_external'
} ]
"""
cnx = ndb.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
cursor.execute(
"""
SELECT DISTINCT SFV.*, ue.ue_code
FROM notes_ue ue, notes_formations nf,
notes_formations nf2, scolar_formsemestre_validation SFV, notes_formsemestre sem
WHERE ue.formation_id = nf.id
and nf.formation_code = nf2.formation_code
and nf2.id=%(formation_id)s
and SFV.ue_id = ue.id
and SFV.code = 'ADM'
and SFV.etudid = %(etudid)s
and ( (sem.id = SFV.formsemestre_id
and sem.date_debut < %(date_debut)s
and sem.semestre_id = %(semestre_id)s )
or (
((SFV.formsemestre_id is NULL) OR (SFV.is_external)) -- les UE externes ou "anterieures"
AND (SFV.semestre_id is NULL OR SFV.semestre_id=%(semestre_id)s)
) )
""",
{
"etudid": etudid,
"formation_id": formation_id,
"semestre_id": semestre_idx,
"date_debut": date_debut,
},
)
return cursor.dictfetchall()
def list_formsemestre_utilisateurs_uecap(formsemestre_id):
"""Liste des formsemestres pouvant utiliser une UE capitalisee de ce semestre
(et qui doivent donc etre sortis du cache si l'on modifie ce
semestre): meme code formation, meme semestre_id, date posterieure"""
cnx = ndb.GetDBConnexion()
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
cursor.execute(
"""SELECT sem.id
FROM notes_formsemestre sem, notes_formations F
WHERE sem.formation_id = F.id
and F.formation_code = %(formation_code)s
and sem.semestre_id = %(semestre_id)s
and sem.date_debut >= %(date_debut)s
and sem.id != %(formsemestre_id)s;
""",
{
"formation_code": F["formation_code"],
"semestre_id": sem["semestre_id"],
"formsemestre_id": formsemestre_id,
"date_debut": ndb.DateDMYtoISO(sem["date_debut"]),
},
)
return [x[0] for x in cursor.fetchall()]

View File

@ -28,9 +28,10 @@
"""Semestres: gestion parcours DUT (Arreté du 13 août 2005)
"""
from app import db
from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre, UniteEns
from app.models import FormSemestre, UniteEns, ScolarAutorisationInscription
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
@ -105,27 +106,14 @@ class DecisionSem(object):
)
)
)
# xxx debug
# log('%s: %s %s %s %s %s' % (self.codechoice,code_etat,new_code_prev,formsemestre_id_utilise_pour_compenser,devenir,assiduite) )
def SituationEtudParcours(etud: dict, formsemestre_id: int):
"""renvoie une instance de SituationEtudParcours (ou sous-classe spécialisée)"""
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
# if formsemestre.formation.is_apc():
# return SituationEtudParcoursBUT(etud, formsemestre_id, nt)
parcours = nt.parcours
#
if parcours.ECTS_ONLY:
return SituationEtudParcoursECTS(etud, formsemestre_id, nt)
else:
return SituationEtudParcoursGeneric(etud, formsemestre_id, nt)
class SituationEtudCursus:
"Semestre dans un cursus"
pass
class SituationEtudParcoursGeneric:
class SituationEtudCursusClassic(SituationEtudCursus):
"Semestre dans un parcours"
def __init__(self, etud: dict, formsemestre_id: int, nt: NotesTableCompat):
@ -454,8 +442,7 @@ class SituationEtudParcoursGeneric:
break
if not cur or cur["formsemestre_id"] != self.formsemestre_id:
log(
"*** SituationEtudParcours: search_prev: cur not found (formsemestre_id=%s, etudid=%s)"
% (self.formsemestre_id, self.etudid)
f"*** SituationEtudCursus: search_prev: cur not found (formsemestre_id={self.formsemestre_id}, etudid={self.etudid})"
)
return None # pas de semestre courant !!!
# Cherche semestre antérieur de même formation (code) et semestre_id precedent
@ -633,31 +620,27 @@ class SituationEtudParcoursGeneric:
formsemestre_id=self.prev["formsemestre_id"]
) # > modif decisions jury (sem, UE)
# -- supprime autorisations venant de ce formsemestre
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
try:
cursor.execute(
"""delete from scolar_autorisation_inscription
where etudid = %(etudid)s and origin_formsemestre_id=%(origin_formsemestre_id)s
""",
{"etudid": self.etudid, "origin_formsemestre_id": self.formsemestre_id},
# -- Supprime autorisations venant de ce formsemestre
autorisations = ScolarAutorisationInscription.query.filter_by(
etudid=self.etudid, origin_formsemestre_id=self.formsemestre_id
)
# -- enregistre autorisations inscription
for autorisation in autorisations:
db.session.delete(autorisation)
db.session.flush()
# -- Enregistre autorisations inscription
next_semestre_ids = self.get_next_semestre_ids(decision.devenir)
for next_semestre_id in next_semestre_ids:
_scolar_autorisation_inscription_editor.create(
cnx,
{
"etudid": self.etudid,
"formation_code": self.formation.formation_code,
"semestre_id": next_semestre_id,
"origin_formsemestre_id": self.formsemestre_id,
},
autorisation = ScolarAutorisationInscription(
etudid=self.etudid,
formation_code=self.formation.formation_code,
semestre_id=next_semestre_id,
origin_formsemestre_id=self.formsemestre_id,
)
cnx.commit()
db.session.add(autorisation)
db.session.commit()
except:
cnx.rollback()
cnx.session.rollback()
raise
sco_cache.invalidate_formsemestre(
formsemestre_id=self.formsemestre_id
@ -673,11 +656,11 @@ class SituationEtudParcoursGeneric:
) # > modif decision jury
class SituationEtudParcoursECTS(SituationEtudParcoursGeneric):
class SituationEtudCursusECTS(SituationEtudCursusClassic):
"""Gestion parcours basés sur ECTS"""
def __init__(self, etud, formsemestre_id, nt):
SituationEtudParcoursGeneric.__init__(self, etud, formsemestre_id, nt)
SituationEtudCursusClassic.__init__(self, etud, formsemestre_id, nt)
def could_be_compensated(self):
return False # jamais de compensations dans ce parcours
@ -1032,102 +1015,3 @@ def etud_est_inscrit_ue(cnx, etudid, formsemestre_id, ue_id):
)
return len(cursor.fetchall())
_scolar_autorisation_inscription_editor = ndb.EditableTable(
"scolar_autorisation_inscription",
"autorisation_inscription_id",
("etudid", "formation_code", "semestre_id", "date", "origin_formsemestre_id"),
output_formators={"date": ndb.DateISOtoDMY},
input_formators={"date": ndb.DateDMYtoISO},
)
scolar_autorisation_inscription_list = _scolar_autorisation_inscription_editor.list
def formsemestre_get_autorisation_inscription(etudid, origin_formsemestre_id):
"""Liste des autorisations d'inscription pour cet étudiant
émanant du semestre indiqué.
"""
cnx = ndb.GetDBConnexion()
return scolar_autorisation_inscription_list(
cnx, {"origin_formsemestre_id": origin_formsemestre_id, "etudid": etudid}
)
def formsemestre_get_etud_capitalisation(
formation_id: int, semestre_idx: int, date_debut, etudid: int
) -> list[dict]:
"""Liste des UE capitalisées (ADM) correspondant au semestre sem et à l'étudiant.
Recherche dans les semestres de la même formation (code) avec le même
semestre_id et une date de début antérieure à celle du semestre mentionné.
Et aussi les UE externes validées.
Resultat: [ { 'formsemestre_id' :
'ue_id' : ue_id dans le semestre origine
'ue_code' :
'moy_ue' :
'event_date' :
'is_external'
} ]
"""
cnx = ndb.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
cursor.execute(
"""
SELECT DISTINCT SFV.*, ue.ue_code
FROM notes_ue ue, notes_formations nf,
notes_formations nf2, scolar_formsemestre_validation SFV, notes_formsemestre sem
WHERE ue.formation_id = nf.id
and nf.formation_code = nf2.formation_code
and nf2.id=%(formation_id)s
and SFV.ue_id = ue.id
and SFV.code = 'ADM'
and SFV.etudid = %(etudid)s
and ( (sem.id = SFV.formsemestre_id
and sem.date_debut < %(date_debut)s
and sem.semestre_id = %(semestre_id)s )
or (
((SFV.formsemestre_id is NULL) OR (SFV.is_external)) -- les UE externes ou "anterieures"
AND (SFV.semestre_id is NULL OR SFV.semestre_id=%(semestre_id)s)
) )
""",
{
"etudid": etudid,
"formation_id": formation_id,
"semestre_id": semestre_idx,
"date_debut": date_debut,
},
)
return cursor.dictfetchall()
def list_formsemestre_utilisateurs_uecap(formsemestre_id):
"""Liste des formsemestres pouvant utiliser une UE capitalisee de ce semestre
(et qui doivent donc etre sortis du cache si l'on modifie ce
semestre): meme code formation, meme semestre_id, date posterieure"""
cnx = ndb.GetDBConnexion()
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
cursor.execute(
"""SELECT sem.id
FROM notes_formsemestre sem, notes_formations F
WHERE sem.formation_id = F.id
and F.formation_code = %(formation_code)s
and sem.semestre_id = %(semestre_id)s
and sem.date_debut >= %(date_debut)s
and sem.id != %(formsemestre_id)s;
""",
{
"formation_code": F["formation_code"],
"semestre_id": sem["semestre_id"],
"formsemestre_id": formsemestre_id,
"date_debut": ndb.DateDMYtoISO(sem["date_debut"]),
},
)
return [x[0] for x in cursor.fetchall()]

View File

@ -140,7 +140,7 @@ def do_ue_create(args):
def do_ue_delete(ue_id, delete_validations=False, force=False):
"delete UE and attached matieres (but not modules)"
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_cursus_dut
ue = UniteEns.query.get_or_404(ue_id)
formation = ue.formation
@ -164,7 +164,7 @@ def do_ue_delete(ue_id, delete_validations=False, force=False):
# raise ScoLockedFormError()
# Il y a-t-il des etudiants ayant validé cette UE ?
# si oui, propose de supprimer les validations
validations = sco_parcours_dut.scolar_formsemestre_validation_list(
validations = sco_cursus_dut.scolar_formsemestre_validation_list(
cnx, args={"ue_id": ue.id}
)
if validations and not delete_validations and not force:

View File

@ -60,7 +60,7 @@ from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups_copy
from app.scodoc import sco_modalites
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_cursus_dut
from app.scodoc import sco_permissions_check
from app.scodoc import sco_portal_apogee
from app.scodoc import sco_preferences
@ -1362,14 +1362,14 @@ def _reassociate_moduleimpls(cnx, formsemestre_id, ues_old2new, modules_old2new)
if e["ue_id"]:
e["ue_id"] = ues_old2new[e["ue_id"]]
sco_etud.scolar_events_edit(cnx, e)
validations = sco_parcours_dut.scolar_formsemestre_validation_list(
validations = sco_cursus_dut.scolar_formsemestre_validation_list(
cnx, args={"formsemestre_id": formsemestre_id}
)
for e in validations:
if e["ue_id"]:
e["ue_id"] = ues_old2new[e["ue_id"]]
# log('e=%s' % e )
sco_parcours_dut.scolar_formsemestre_validation_edit(cnx, e)
sco_cursus_dut.scolar_formsemestre_validation_edit(cnx, e)
def formsemestre_delete(formsemestre_id):

View File

@ -51,7 +51,7 @@ from app.scodoc import sco_formations
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_formsemestre_validation
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_cursus_dut
from app.scodoc import sco_etud
@ -450,7 +450,7 @@ def _list_ue_with_coef_and_validations(sem, etudid):
else:
ue["uecoef"] = {}
# add validation
validation = sco_parcours_dut.scolar_formsemestre_validation_list(
validation = sco_cursus_dut.scolar_formsemestre_validation_list(
cnx,
args={
"formsemestre_id": formsemestre_id,

View File

@ -59,8 +59,9 @@ from app.scodoc import sco_edit_ue
from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_parcours_dut
from app.scodoc.sco_parcours_dut import etud_est_inscrit_ue
from app.scodoc import sco_cursus
from app.scodoc import sco_cursus_dut
from app.scodoc.sco_cursus_dut import etud_est_inscrit_ue
from app.scodoc import sco_photos
from app.scodoc import sco_preferences
from app.scodoc import sco_pvjury
@ -108,7 +109,7 @@ def formsemestre_validation_etud_form(
check = True
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
Se = sco_parcours_dut.SituationEtudParcours(etud, formsemestre_id)
Se = sco_cursus.get_situation_etud_cursus(etud, formsemestre_id)
if not Se.sem["etat"]:
raise ScoValueError("validation: semestre verrouille")
@ -274,15 +275,12 @@ def formsemestre_validation_etud_form(
ass = "non assidu"
H.append("<p>Décision existante du %(event_date)s: %(code)s" % decision_jury)
H.append(" (%s)" % ass)
auts = sco_parcours_dut.formsemestre_get_autorisation_inscription(
etudid, formsemestre_id
)
if auts:
autorisations = ScolarAutorisationInscription.query.filter_by(
etudid=etudid, origin_formsemestre_id=formsemestre_id
).all()
if autorisations:
H.append(". Autorisé%s à s'inscrire en " % etud["ne"])
alist = []
for aut in auts:
alist.append(str(aut["semestre_id"]))
H.append(", ".join(["S%s" % x for x in alist]) + ".")
H.append(", ".join([f"S{aut.semestre_id}" for aut in autorisations]) + ".")
H.append("</p>")
# Cas particulier pour ATJ: corriger precedent avant de continuer
@ -382,7 +380,7 @@ def formsemestre_validation_etud(
):
"""Enregistre validation"""
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
Se = sco_parcours_dut.SituationEtudParcours(etud, formsemestre_id)
Se = sco_cursus.get_situation_etud_cursus(etud, formsemestre_id)
# retrouve la decision correspondant au code:
choices = Se.get_possible_choices(assiduite=True)
choices += Se.get_possible_choices(assiduite=False)
@ -415,7 +413,7 @@ def formsemestre_validation_etud_manu(
if assidu:
assidu = True
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
Se = sco_parcours_dut.SituationEtudParcours(etud, formsemestre_id)
Se = sco_cursus.get_situation_etud_cursus(etud, formsemestre_id)
if code_etat in Se.parcours.UNUSED_CODES:
raise ScoValueError("code decision invalide dans ce parcours")
# Si code ADC, extrait le semestre utilisé:
@ -430,7 +428,7 @@ def formsemestre_validation_etud_manu(
formsemestre_id_utilise_pour_compenser = None
# Construit le choix correspondant:
choice = sco_parcours_dut.DecisionSem(
choice = sco_cursus_dut.DecisionSem(
code_etat=code_etat,
new_code_prev=new_code_prev,
devenir=devenir,
@ -910,7 +908,7 @@ def do_formsemestre_validation_auto(formsemestre_id):
conflicts = [] # liste des etudiants avec decision differente déjà saisie
for etudid in etudids:
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
Se = sco_parcours_dut.SituationEtudParcours(etud, formsemestre_id)
Se = sco_cursus.get_situation_etud_cursus(etud, formsemestre_id)
ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
{"etudid": etudid, "formsemestre_id": formsemestre_id}
)[0]
@ -932,15 +930,13 @@ def do_formsemestre_validation_auto(formsemestre_id):
if decision_sem and decision_sem["code"] != ADM:
ok = False
conflicts.append(etud)
autorisations = sco_parcours_dut.formsemestre_get_autorisation_inscription(
etudid, formsemestre_id
)
if (
len(autorisations) != 0
): # accepte le cas ou il n'y a pas d'autorisation : BUG 23/6/7, A RETIRER ENSUITE
autorisations = ScolarAutorisationInscription.query.filter_by(
etudid=etudid, origin_formsemestre_id=formsemestre_id
).all()
if len(autorisations) != 0:
if (
len(autorisations) != 1
or autorisations[0]["semestre_id"] != next_semestre_id
len(autorisations) > 1
or autorisations[0].semestre_id != next_semestre_id
):
if ok:
conflicts.append(etud)
@ -1176,7 +1172,7 @@ def do_formsemestre_validate_previous_ue(
)
else:
sco_formsemestre.do_formsemestre_uecoef_delete(cnx, formsemestre_id, ue_id)
sco_parcours_dut.do_formsemestre_validate_ue(
sco_cursus_dut.do_formsemestre_validate_ue(
cnx,
nt,
formsemestre_id, # "importe" cette UE dans le semestre (new 3/2015)

View File

@ -56,8 +56,9 @@ import app.scodoc.notesdb as ndb
from app import log, cache
from app.scodoc.scolog import logdb
from app.scodoc import html_sco_header
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_cache
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_cursus
from app.scodoc import sco_etud
from app.scodoc import sco_permissions_check
from app.scodoc import sco_xml
@ -1489,13 +1490,13 @@ def _get_prev_moy(etudid, formsemestre_id):
"""Donne la derniere moyenne generale calculee pour cette étudiant,
ou 0 si on n'en trouve pas (nouvel inscrit,...).
"""
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_cursus_dut
info = sco_etud.get_etud_info(etudid=etudid, filled=True)
if not info:
raise ScoValueError("etudiant invalide: etudid=%s" % etudid)
etud = info[0]
Se = sco_parcours_dut.SituationEtudParcours(etud, formsemestre_id)
Se = sco_cursus.get_situation_etud_cursus(etud, formsemestre_id)
if Se.prev:
prev_sem = FormSemestre.query.get(Se.prev["formsemestre_id"])
nt: NotesTableCompat = res_sem.load_formsemestre_results(prev_sem)

View File

@ -49,7 +49,7 @@ from app.scodoc import sco_excel
from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_cursus
from app.scodoc import sco_portal_apogee
from app.scodoc import sco_preferences
from app.scodoc import sco_etud
@ -776,7 +776,7 @@ def groups_table(
m.update(etud)
sco_etud.etud_add_lycee_infos(etud)
# et ajoute le parcours
Se = sco_parcours_dut.SituationEtudParcours(
Se = sco_cursus.get_situation_etud_cursus(
etud, groups_infos.formsemestre_id
)
m["parcours"] = Se.get_parcours_descr()

View File

@ -39,7 +39,7 @@ from app.models import ModuleImpl
from app.models.evaluations import Evaluation
import app.scodoc.sco_utils as scu
from app.scodoc.sco_exceptions import ScoInvalidIdType
from app.scodoc.sco_parcours_dut import formsemestre_has_decisions
from app.scodoc.sco_cursus_dut import formsemestre_has_decisions
from app.scodoc.sco_permissions import Permission
from app.scodoc import html_sco_header

View File

@ -46,7 +46,7 @@ from app.scodoc import sco_codes_parcours
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_status
from app.scodoc import sco_groups
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_cursus
from app.scodoc import sco_permissions_check
from app.scodoc import sco_photos
from app.scodoc import sco_users
@ -269,7 +269,7 @@ def ficheEtud(etudid=None):
sem_info[sem["formsemestre_id"]] = grlink
if info["sems"]:
Se = sco_parcours_dut.SituationEtudParcours(etud, info["last_formsemestre_id"])
Se = sco_cursus.get_situation_etud_cursus(etud, info["last_formsemestre_id"])
info["liste_inscriptions"] = formsemestre_recap_parcours_table(
Se,
etudid,

View File

@ -24,14 +24,14 @@ def can_edit_notes(authuser, moduleimpl_id, allow_ens=True):
seul le directeur des études peut saisir des notes (et il ne devrait pas).
"""
from app.scodoc import sco_formsemestre
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_cursus_dut
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
if not sem["etat"]:
return False # semestre verrouillé
if sco_parcours_dut.formsemestre_has_decisions(sem["formsemestre_id"]):
if sco_cursus_dut.formsemestre_has_decisions(sem["formsemestre_id"]):
# il y a des décisions de jury dans ce semestre !
return (
authuser.has_permission(Permission.ScoEditAllNotes)

View File

@ -37,14 +37,14 @@ from flask_login import current_user
from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre, Identite
from app.models import FormSemestre, Identite, ScolarAutorisationInscription
from app.scodoc import sco_abs
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_groups
from app.scodoc import sco_etud
from app.scodoc import sco_excel
from app.scodoc import sco_formsemestre
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_cursus
from app.scodoc import sco_preferences
import app.scodoc.sco_utils as scu
import sco_version
@ -78,7 +78,7 @@ def feuille_preparation_jury(formsemestre_id):
nbabs = {}
nbabsjust = {}
for etud in etuds:
Se = sco_parcours_dut.SituationEtudParcours(
Se = sco_cursus.get_situation_etud_cursus(
etud.to_dict_scodoc7(), formsemestre_id
)
if Se.prev:
@ -119,10 +119,11 @@ def feuille_preparation_jury(formsemestre_id):
if decision["compense_formsemestre_id"]:
code[etud.id] += "+" # indique qu'il a servi a compenser
assidu[etud.id] = {False: "Non", True: "Oui"}.get(decision["assidu"], "")
aut_list = sco_parcours_dut.formsemestre_get_autorisation_inscription(
etud.id, formsemestre_id
)
autorisations[etud.id] = ", ".join(["S%s" % x["semestre_id"] for x in aut_list])
autorisations = 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])
# parcours:
parcours[etud.id] = Se.get_parcours_descr()
# groupe principal (td)

View File

@ -57,24 +57,24 @@ from flask import g, request
from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre, UniteEns
from app.models import FormSemestre, UniteEns, ScolarAutorisationInscription
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app import log
from app.scodoc import html_sco_header
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_cache
from app.scodoc import sco_cursus
from app.scodoc import sco_cursus_dut
from app.scodoc import sco_edit_ue
from app.scodoc import sco_etud
from app.scodoc import sco_formations
from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups
from app.scodoc import sco_groups_view
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_pdf
from app.scodoc import sco_preferences
from app.scodoc import sco_pvpdf
from app.scodoc import sco_etud
from app.scodoc.gen_tables import GenTable
from app.scodoc.sco_codes_parcours import NO_SEMESTRE_ID
from app.scodoc.sco_pdf import PDFLOCK
@ -138,12 +138,9 @@ def _descr_decision_sem_abbrev(etat, decision_sem):
return decision
def descr_autorisations(autorisations):
def descr_autorisations(autorisations: list[ScolarAutorisationInscription]) -> str:
"résumé textuel des autorisations d'inscription (-> 'S1, S3' )"
alist = []
for aut in autorisations:
alist.append("S" + str(aut["semestre_id"]))
return ", ".join(alist)
return ", ".join([f"S{a.semestre_id}" for a in autorisations])
def _comp_ects_by_ue_code(nt, decision_ues):
@ -234,7 +231,7 @@ def dict_pvjury(
D = {} # même chose que L, mais { etudid : dec }
for etudid in etudids:
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
Se = sco_parcours_dut.SituationEtudParcours(etud, formsemestre_id)
Se = sco_cursus.get_situation_etud_cursus(etud, formsemestre_id)
semestre_non_terminal = semestre_non_terminal or Se.semestre_non_terminal
d = {}
d["identite"] = nt.identdict[etudid]
@ -280,17 +277,18 @@ def dict_pvjury(
else:
d["decision_sem_descr"] = _descr_decision_sem(d["etat"], d["decision_sem"])
d["autorisations"] = sco_parcours_dut.formsemestre_get_autorisation_inscription(
etudid, formsemestre_id
)
d["autorisations_descr"] = descr_autorisations(d["autorisations"])
autorisations = ScolarAutorisationInscription.query.filter_by(
etudid=etudid, origin_formsemestre_id=formsemestre_id
).all()
d["autorisations"] = [a.to_dict() for a in autorisations]
d["autorisations_descr"] = descr_autorisations(autorisations)
d["validation_parcours"] = Se.parcours_validated()
d["parcours"] = Se.get_parcours_descr(filter_futur=True)
if with_parcours_decisions:
d["parcours_decisions"] = Se.get_parcours_decisions()
# Observations sur les compensations:
compensators = sco_parcours_dut.scolar_formsemestre_validation_list(
compensators = sco_cursus_dut.scolar_formsemestre_validation_list(
cnx, args={"compense_formsemestre_id": formsemestre_id, "etudid": etudid}
)
obs = []

View File

@ -50,7 +50,7 @@ from app.scodoc import sco_formsemestre
from app.scodoc import sco_pdf
from app.scodoc import sco_preferences
from app.scodoc.sco_logos import find_logo
from app.scodoc.sco_parcours_dut import SituationEtudParcours
from app.scodoc.sco_cursus_dut import SituationEtudCursus
from app.scodoc.sco_pdf import SU
import sco_version
@ -428,7 +428,7 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None):
"""
#
formsemestre_id = sem["formsemestre_id"]
Se: SituationEtudParcours = decision["Se"]
Se: SituationEtudCursus = decision["Se"]
t, s = _descr_jury(sem, Se.parcours_validated() or not Se.semestre_non_terminal)
objects = []
style = reportlab.lib.styles.ParagraphStyle({})

View File

@ -41,7 +41,7 @@ import pydot
from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre
from app.models import FormSemestre, ScolarAutorisationInscription
import app.scodoc.sco_utils as scu
from app.models import FormationModalite
@ -51,7 +51,6 @@ from app.scodoc import sco_codes_parcours
from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_preferences
import sco_version
from app.scodoc.gen_tables import GenTable
@ -81,10 +80,10 @@ def formsemestre_etuds_stats(sem, only_primo=False):
if "codedecision" not in etud:
etud["codedecision"] = "(nd)" # pas de decision jury
# Ajout devenir (autorisations inscriptions), utile pour stats passage
aut_list = sco_parcours_dut.formsemestre_get_autorisation_inscription(
etudid, sem["formsemestre_id"]
)
autorisations = ["S%s" % x["semestre_id"] for x in aut_list]
aut_list = ScolarAutorisationInscription.query.filter_by(
etudid=etudid, origin_formsemestre_id=sem["formsemestre_id"]
).all()
autorisations = [f"S{a.semestre_id}" for a in aut_list]
autorisations.sort()
autorisations_str = ", ".join(autorisations)
etud["devenir"] = autorisations_str

View File

@ -20,6 +20,7 @@ from config import TestConfig
from tests.unit import sco_fake_gen
import app
from app import db
from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre
@ -31,8 +32,7 @@ from app.scodoc import sco_codes_parcours
from app.scodoc import sco_evaluations
from app.scodoc import sco_evaluation_db
from app.scodoc import sco_formsemestre_validation
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_cache
from app.scodoc import sco_cursus_dut
from app.scodoc import sco_saisie_notes
from app.scodoc import sco_utils as scu
@ -194,20 +194,20 @@ def run_sco_basic(verbose=False):
# --- Permission saisie notes et décisions de jury, avec ou sans démission ou défaillance
# on n'a pas encore saisi de décisions
assert not sco_parcours_dut.formsemestre_has_decisions(formsemestre_id)
assert not sco_cursus_dut.formsemestre_has_decisions(formsemestre_id)
# Saisie d'un décision AJ, non assidu
etudid = etuds[-1]["etudid"]
sco_parcours_dut.formsemestre_validate_ues(
sco_cursus_dut.formsemestre_validate_ues(
formsemestre_id, etudid, sco_codes_parcours.AJ, False
)
assert sco_parcours_dut.formsemestre_has_decisions(
assert sco_cursus_dut.formsemestre_has_decisions(
formsemestre_id
), "décisions manquantes"
# Suppression de la décision
sco_formsemestre_validation.formsemestre_validation_suppress_etud(
formsemestre_id, etudid
)
assert not sco_parcours_dut.formsemestre_has_decisions(
assert not sco_cursus_dut.formsemestre_has_decisions(
formsemestre_id
), "décisions non effacées"