Cascades sur Identite. Inscription aux parcours BUT.

This commit is contained in:
Emmanuel Viennet 2022-05-26 03:55:03 +02:00
commit 3c9cc3121f
18 changed files with 430 additions and 40 deletions

View File

@ -4,7 +4,6 @@
# See LICENSE # See LICENSE
############################################################################## ##############################################################################
from xml.etree import ElementTree from xml.etree import ElementTree
from typing import TextIO
import sqlalchemy import sqlalchemy

View File

@ -70,6 +70,7 @@ class ResultatsSemestre(ResultatsCache):
self.etud_moy_gen: pd.Series = None self.etud_moy_gen: pd.Series = None
self.etud_moy_gen_ranks = {} self.etud_moy_gen_ranks = {}
self.etud_moy_gen_ranks_int = {} self.etud_moy_gen_ranks_int = {}
self.moy_gen_rangs_by_group = None # virtual
self.modimpl_inscr_df: pd.DataFrame = None self.modimpl_inscr_df: pd.DataFrame = None
"Inscriptions: row etudid, col modimlpl_id" "Inscriptions: row etudid, col modimlpl_id"
self.modimpls_results: ModuleImplResults = None self.modimpls_results: ModuleImplResults = None
@ -824,17 +825,25 @@ class ResultatsSemestre(ResultatsCache):
self.formsemestre.id self.formsemestre.id
) )
first_partition = True first_partition = True
col_order = 10
for partition in partitions: for partition in partitions:
cid = f"part_{partition['partition_id']}" cid = f"part_{partition['partition_id']}"
rg_cid = cid + "_rg" # rang dans la partition
titles[cid] = partition["partition_name"] titles[cid] = partition["partition_name"]
if first_partition: if first_partition:
klass = "partition" klass = "partition"
else: else:
klass = "partition partition_aux" klass = "partition partition_aux"
titles[f"_{cid}_class"] = klass titles[f"_{cid}_class"] = klass
titles[f"_{cid}_col_order"] = 10 titles[f"_{cid}_col_order"] = col_order
titles[f"_{rg_cid}_col_order"] = col_order + 1
col_order += 2
if partition["bul_show_rank"]:
titles[rg_cid] = f"Rg {partition['partition_name']}"
titles[f"_{rg_cid}_class"] = "partition_rangs"
partition_etud_groups = partitions_etud_groups[partition["partition_id"]] partition_etud_groups = partitions_etud_groups[partition["partition_id"]]
for row in rows: for row in rows:
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 == "D":
@ -847,8 +856,17 @@ class ResultatsSemestre(ResultatsCache):
group = partition_etud_groups.get(row["etudid"]) group = partition_etud_groups.get(row["etudid"])
gr_name = group["group_name"] if group else "" gr_name = group["group_name"] if group else ""
if gr_name: if gr_name:
row[f"{cid}"] = gr_name row[cid] = gr_name
row[f"_{cid}_class"] = klass row[f"_{cid}_class"] = klass
# Rangs dans groupe
if (
partition["bul_show_rank"]
and (group is not None)
and (group["id"] in self.moy_gen_rangs_by_group)
):
rang = self.moy_gen_rangs_by_group[group["id"]][0]
row[rg_cid] = rang.get(row["etudid"], "")
first_partition = False first_partition = False
def _recap_add_evaluations( def _recap_add_evaluations(

View File

@ -11,7 +11,9 @@ class Absence(db.Model):
__tablename__ = "absences" __tablename__ = "absences"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
etudid = db.Column(db.Integer, db.ForeignKey("identite.id"), index=True) etudid = db.Column(
db.Integer, db.ForeignKey("identite.id", ondelete="CASCADE"), index=True
)
jour = db.Column(db.Date) jour = db.Column(db.Date)
estabs = db.Column(db.Boolean()) estabs = db.Column(db.Boolean())
estjust = db.Column(db.Boolean()) estjust = db.Column(db.Boolean())
@ -50,7 +52,7 @@ class AbsenceNotification(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
etudid = db.Column( etudid = db.Column(
db.Integer, db.Integer,
db.ForeignKey("identite.id"), db.ForeignKey("identite.id", ondelete="CASCADE"),
) )
notification_date = db.Column( notification_date = db.Column(
db.DateTime(timezone=True), server_default=db.func.now() db.DateTime(timezone=True), server_default=db.func.now()

View File

@ -436,7 +436,7 @@ class Adresse(db.Model):
adresse_id = db.synonym("id") adresse_id = db.synonym("id")
etudid = db.Column( etudid = db.Column(
db.Integer, db.Integer,
db.ForeignKey("identite.id"), db.ForeignKey("identite.id", ondelete="CASCADE"),
) )
email = db.Column(db.Text()) # mail institutionnel email = db.Column(db.Text()) # mail institutionnel
emailperso = db.Column(db.Text) # email personnel (exterieur) emailperso = db.Column(db.Text) # email personnel (exterieur)
@ -470,7 +470,7 @@ class Admission(db.Model):
adm_id = db.synonym("id") adm_id = db.synonym("id")
etudid = db.Column( etudid = db.Column(
db.Integer, db.Integer,
db.ForeignKey("identite.id"), db.ForeignKey("identite.id", ondelete="CASCADE"),
) )
# Anciens champs de ScoDoc7, à revoir pour être plus générique et souple # Anciens champs de ScoDoc7, à revoir pour être plus générique et souple
# notamment dans le cadre du bac 2021 # notamment dans le cadre du bac 2021
@ -540,7 +540,7 @@ class ItemSuivi(db.Model):
itemsuivi_id = db.synonym("id") itemsuivi_id = db.synonym("id")
etudid = db.Column( etudid = db.Column(
db.Integer, db.Integer,
db.ForeignKey("identite.id"), db.ForeignKey("identite.id", ondelete="CASCADE"),
) )
item_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) item_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
situation = db.Column(db.Text) situation = db.Column(db.Text)

View File

@ -323,6 +323,25 @@ class FormSemestre(db.Model):
return "" return ""
return ", ".join(sorted([etape.etape_apo for etape in self.etapes if etape])) return ", ".join(sorted([etape.etape_apo for etape in self.etapes if etape]))
def regroupements_coherents_etud(self) -> list[tuple[UniteEns, UniteEns]]:
"""Calcule la liste des regroupements cohérents d'UE impliquant ce
formsemestre.
Pour une année donnée: l'étudiant est inscrit dans ScoDoc soit dans le semestre
impair, soit pair, soit les deux (il est rare mais pas impossible d'avoir une
inscription seulement en semestre pair, par exemple suite à un transfert ou un
arrêt temporaire du cursus).
1. Déterminer l'*autre* formsemestre: semestre précédent ou suivant de la même
année, formation compatible (même référentiel de compétence) dans lequel
l'étudiant est inscrit.
2. Construire les couples d'UE (regroupements cohérents): apparier les UE qui
ont le même `ApcParcoursNiveauCompetence`.
"""
if not self.formation.is_apc():
return []
raise NotImplementedError() # XXX
def responsables_str(self, abbrev_prenom=True) -> str: def responsables_str(self, abbrev_prenom=True) -> str:
"""chaîne "J. Dupond, X. Martin" """chaîne "J. Dupond, X. Martin"
ou "Jacques Dupond, Xavier Martin" ou "Jacques Dupond, Xavier Martin"
@ -614,7 +633,9 @@ class FormSemestreInscription(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
formsemestre_inscription_id = db.synonym("id") formsemestre_inscription_id = db.synonym("id")
etudid = db.Column(db.Integer, db.ForeignKey("identite.id"), index=True) etudid = db.Column(
db.Integer, db.ForeignKey("identite.id", ondelete="CASCADE"), index=True
)
formsemestre_id = db.Column( formsemestre_id = db.Column(
db.Integer, db.Integer,
db.ForeignKey("notes_formsemestre.id"), db.ForeignKey("notes_formsemestre.id"),
@ -634,11 +655,16 @@ class FormSemestreInscription(db.Model):
) )
# I inscrit, D demission en cours de semestre, DEF si "defaillant" # I inscrit, D demission en cours de semestre, DEF si "defaillant"
etat = db.Column(db.String(CODE_STR_LEN), index=True) etat = db.Column(db.String(CODE_STR_LEN), index=True)
# etape apogee d'inscription (experimental 2020) # Etape Apogée d'inscription (ajout 2020)
etape = db.Column(db.String(APO_CODE_STR_LEN)) etape = db.Column(db.String(APO_CODE_STR_LEN))
# Parcours (pour les BUT)
parcour_id = db.Column(db.Integer, db.ForeignKey("apc_parcours.id"), index=True)
parcour = db.relationship(ApcParcours)
def __repr__(self): def __repr__(self):
return f"<{self.__class__.__name__} {self.id} etudid={self.etudid} sem={self.formsemestre_id} etat={self.etat}>" return f"""<{self.__class__.__name__} {self.id} etudid={self.etudid} sem={
self.formsemestre_id} etat={self.etat} {
('parcours='+str(self.parcour)) if self.parcour else ''}>"""
class NotesSemSet(db.Model): class NotesSemSet(db.Model):

View File

@ -106,7 +106,7 @@ class GroupDescr(db.Model):
group_membership = db.Table( group_membership = db.Table(
"group_membership", "group_membership",
db.Column("etudid", db.Integer, db.ForeignKey("identite.id")), db.Column("etudid", db.Integer, db.ForeignKey("identite.id", ondelete="CASCADE")),
db.Column("group_id", db.Integer, db.ForeignKey("group_descr.id")), db.Column("group_id", db.Integer, db.ForeignKey("group_descr.id")),
db.UniqueConstraint("etudid", "group_id"), db.UniqueConstraint("etudid", "group_id"),
) )
@ -116,5 +116,5 @@ group_membership = db.Table(
# __tablename__ = "group_membership" # __tablename__ = "group_membership"
# __table_args__ = (db.UniqueConstraint("etudid", "group_id"),) # __table_args__ = (db.UniqueConstraint("etudid", "group_id"),)
# id = db.Column(db.Integer, primary_key=True) # id = db.Column(db.Integer, primary_key=True)
# etudid = db.Column(db.Integer, db.ForeignKey("identite.id")) # etudid = db.Column(db.Integer, db.ForeignKey("identite.id", ondelete="CASCADE"))
# group_id = db.Column(db.Integer, db.ForeignKey("group_descr.id")) # group_id = db.Column(db.Integer, db.ForeignKey("group_descr.id"))

View File

@ -17,7 +17,7 @@ class BulAppreciations(db.Model):
date = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
etudid = db.Column( etudid = db.Column(
db.Integer, db.Integer,
db.ForeignKey("identite.id"), db.ForeignKey("identite.id", ondelete="CASCADE"),
index=True, index=True,
) )
formsemestre_id = db.Column( formsemestre_id = db.Column(
@ -36,7 +36,7 @@ class NotesNotes(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
etudid = db.Column( etudid = db.Column(
db.Integer, db.Integer,
db.ForeignKey("identite.id"), db.ForeignKey("identite.id", ondelete="CASCADE"),
) )
evaluation_id = db.Column( evaluation_id = db.Column(
db.Integer, db.ForeignKey("notes_evaluation.id"), index=True db.Integer, db.ForeignKey("notes_evaluation.id"), index=True
@ -56,7 +56,7 @@ class NotesNotesLog(db.Model):
etudid = db.Column( etudid = db.Column(
db.Integer, db.Integer,
db.ForeignKey("identite.id"), db.ForeignKey("identite.id", ondelete="CASCADE"),
) )
evaluation_id = db.Column( evaluation_id = db.Column(
db.Integer, db.Integer,

View File

@ -19,7 +19,7 @@ class ScolarFormSemestreValidation(db.Model):
formsemestre_validation_id = db.synonym("id") formsemestre_validation_id = db.synonym("id")
etudid = db.Column( etudid = db.Column(
db.Integer, db.Integer,
db.ForeignKey("identite.id"), db.ForeignKey("identite.id", ondelete="CASCADE"),
index=True, index=True,
) )
formsemestre_id = db.Column( formsemestre_id = db.Column(
@ -66,7 +66,7 @@ class ScolarAutorisationInscription(db.Model):
etudid = db.Column( etudid = db.Column(
db.Integer, db.Integer,
db.ForeignKey("identite.id"), db.ForeignKey("identite.id", ondelete="CASCADE"),
) )
formation_code = db.Column(db.String(SHORT_STR_LEN), nullable=False) formation_code = db.Column(db.String(SHORT_STR_LEN), nullable=False)
# semestre ou on peut s'inscrire: # semestre ou on peut s'inscrire:
@ -86,7 +86,7 @@ class ScolarEvent(db.Model):
event_id = db.synonym("id") event_id = db.synonym("id")
etudid = db.Column( etudid = db.Column(
db.Integer, db.Integer,
db.ForeignKey("identite.id"), db.ForeignKey("identite.id", ondelete="CASCADE"),
) )
event_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) event_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
formsemestre_id = db.Column( formsemestre_id = db.Column(

View File

@ -244,7 +244,11 @@ def formation_edit(formation_id=None, create=False):
return ( return (
"\n".join(H) "\n".join(H)
+ tf_error_message( + tf_error_message(
"Valeurs incorrectes: il existe déjà une formation avec même titre, acronyme et version." f"""Valeurs incorrectes: il existe déjà <a href="{
url_for('notes.ue_table', scodoc_dept=g.scodoc_dept, formation_id=others[0]["id"])
}">une formation</a> avec même titre,
acronyme et version.
"""
) )
+ tf[1] + tf[1]
+ html_sco_header.sco_footer() + html_sco_header.sco_footer()

View File

@ -352,7 +352,7 @@ def module_edit(
title = f"""Création {object_name} dans la formation title = f"""Création {object_name} dans la formation
{formation.acronyme}""" {formation.acronyme}"""
else: else:
page_title = "Modification du module {module.code or module.titre or ''}" page_title = f"Modification du module {module.code or module.titre or ''}"
title = f"""Modification du module {module.code or ''} {module.titre or ''} title = f"""Modification du module {module.code or ''} {module.titre or ''}
(formation {formation.acronyme}, version {formation.version}) (formation {formation.acronyme}, version {formation.version})
""" """

View File

@ -1009,7 +1009,7 @@ def edit_partition_form(formsemestre_id=None):
<input type="submit" name="ok" disabled="1" value="Nouvelle partition"/> <input type="submit" name="ok" disabled="1" value="Nouvelle partition"/>
""" """
) )
if formsemestre.formation.is_apc() and "Parcours" not in ( if formsemestre.formation.is_apc() and scu.PARTITION_PARCOURS not in (
p["partition_name"] for p in partitions p["partition_name"] for p in partitions
): ):
# propose création partition "Parcours" # propose création partition "Parcours"
@ -1068,9 +1068,7 @@ def partition_set_attr(partition_id, attr, value):
partition[attr] = value partition[attr] = value
partitionEditor.edit(cnx, partition) partitionEditor.edit(cnx, partition)
# invalid bulletin cache # invalid bulletin cache
sco_cache.invalidate_formsemestre( sco_cache.invalidate_formsemestre(formsemestre_id=partition["formsemestre_id"])
pdfonly=True, formsemestre_id=partition["formsemestre_id"]
)
return "enregistré" return "enregistré"

View File

@ -111,6 +111,8 @@ MODULE_TYPE_NAMES = {
None: "Module", None: "Module",
} }
PARTITION_PARCOURS = "Parcours"
MALUS_MAX = 20.0 MALUS_MAX = 20.0
MALUS_MIN = -20.0 MALUS_MIN = -20.0

View File

@ -15,13 +15,23 @@ $(function () {
}, },
{ {
name: "toggle_partitions", name: "toggle_partitions",
text: "Toutes les partitions", text: "Montrer groupes",
action: function (e, dt, node, config) { action: function (e, dt, node, config) {
let visible = dt.columns(".partition_aux").visible()[0]; let visible = dt.columns(".partition_aux").visible()[0];
dt.columns(".partition_aux").visible(!visible); dt.columns(".partition_aux").visible(!visible);
dt.buttons('toggle_partitions:name').text(visible ? "Toutes les partitions" : "Cacher les partitions"); dt.buttons('toggle_partitions:name').text(visible ? "Montrer groupes" : "Cacher les groupes");
} }
}]; },
{
name: "toggle_partitions_rangs",
text: "Rangs groupes",
action: function (e, dt, node, config) {
let rangs_visible = dt.columns(".partition_rangs").visible()[0];
dt.columns(".partition_rangs").visible(!rangs_visible);
dt.buttons('toggle_partitions_rangs:name').text(rangs_visible ? "Rangs groupes" : "Cacher rangs groupes");
}
},
];
if (!$('table.table_recap').hasClass("jury")) { if (!$('table.table_recap').hasClass("jury")) {
buttons.push( buttons.push(
$('table.table_recap').hasClass("apc") ? $('table.table_recap').hasClass("apc") ?
@ -95,7 +105,7 @@ $(function () {
"columnDefs": [ "columnDefs": [
{ {
// cache les codes, le détail de l'identité, les groupes, les colonnes admission et les vides // cache les codes, le détail de l'identité, les groupes, les colonnes admission et les vides
targets: ["codes", "identite_detail", "partition_aux", "admission", "col_empty"], targets: ["codes", "identite_detail", "partition_aux", "partition_rangs", "admission", "col_empty"],
visible: false, visible: false,
}, },
{ {

View File

@ -7,8 +7,8 @@
<div class="help"> <div class="help">
<p>Ces codes (ADM, AJ, ...) sont utilisés pour représenter les décisions de jury <p>Ces codes (ADM, AJ, ...) sont utilisés pour représenter les décisions de jury
et les validations de semestres ou d'UE. les valeurs indiquées ici sont utilisées et les validations de semestres ou d'UE.
dans les exports Apogée. Les valeurs indiquées ici sont utilisées dans les exports Apogée.
<p> <p>
<p>Ne les modifier que si vous savez ce que vous faites ! <p>Ne les modifier que si vous savez ce que vous faites !
</p> </p>

View File

@ -15,7 +15,7 @@
<li>Code: <tt>{{ue.ue_code}}</tt></li> <li>Code: <tt>{{ue.ue_code}}</tt></li>
<li>Type: {{ue.type}}</li> <li>Type: {{ue.type}}</li>
<li>Externe: {{ "oui" if ue.is_external else "non" }}</li> <li>Externe: {{ "oui" if ue.is_external else "non" }}</li>
<li>Code Apogée: {{ue.code_apogee}}</li> <li>Code Apogée: {{ue.code_apogee or "aucun"}}</li>
</ul> </ul>
</li> </li>
<li>Formation: <li>Formation:

View File

@ -915,13 +915,14 @@ sco_publish(
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func @scodoc7func
def create_partition_parcours(formsemestre_id): def create_partition_parcours(formsemestre_id):
"""Création d'une partitions nommée "Parcours" avec un groupe par parcours.""" """Création d'une partitions nommée "Parcours" (PARTITION_PARCOURS)
avec un groupe par parcours."""
formsemestre = FormSemestre.query.get_or_404(formsemestre_id) formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
if "Parcours" in (p.partition_name for p in formsemestre.partitions): if scu.PARTITION_PARCOURS in (p.partition_name for p in formsemestre.partitions):
flash("""Partition "Parcours" déjà existante""") flash(f"""Partition "{scu.PARTITION_PARCOURS}" déjà existante""")
else: else:
partition_id = sco_groups.partition_create( partition_id = sco_groups.partition_create(
formsemestre_id, partition_name="Parcours", redirect=False formsemestre_id, partition_name=scu.PARTITION_PARCOURS, redirect=False
) )
n = 0 n = 0
for parcour in formsemestre.parcours: for parcour in formsemestre.parcours:

View File

@ -0,0 +1,308 @@
"""Formsemestre / parcours, Inscriptions aux parcours + cascades sur Identite
Revision ID: a2771105c21c
Revises: 6002d7d366e5
Create Date: 2022-05-25 20:32:06.868296
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "a2771105c21c"
down_revision = "6002d7d366e5"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"parcours_formsemestre",
sa.Column("parcours_id", sa.Integer(), nullable=False),
sa.Column("formsemestre_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(
["formsemestre_id"], ["notes_formsemestre.id"], ondelete="CASCADE"
),
sa.ForeignKeyConstraint(
["parcours_id"],
["apc_parcours.id"],
),
sa.PrimaryKeyConstraint("parcours_id", "formsemestre_id"),
)
op.drop_constraint("absences_etudid_fkey", "absences", type_="foreignkey")
op.create_foreign_key(
"absences_etudid_fkey",
"absences",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint(
"absences_notifications_etudid_fkey",
"absences_notifications",
type_="foreignkey",
)
op.create_foreign_key(
"absences_notifications_etudid_fkey",
"absences_notifications",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint("admissions_etudid_fkey", "admissions", type_="foreignkey")
op.create_foreign_key(
"admissions_etudid_fkey",
"admissions",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint("adresse_etudid_fkey", "adresse", type_="foreignkey")
op.create_foreign_key(
"adresse_etudid_fkey",
"adresse",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint(
"group_membership_etudid_fkey", "group_membership", type_="foreignkey"
)
op.create_foreign_key(
"group_membership_etudid_fkey",
"group_membership",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint("itemsuivi_etudid_fkey", "itemsuivi", type_="foreignkey")
op.create_foreign_key(
"itemsuivi_etudid_fkey",
"itemsuivi",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint(
"notes_appreciations_etudid_fkey", "notes_appreciations", type_="foreignkey"
)
op.create_foreign_key(
"notes_appreciations_etudid_fkey",
"notes_appreciations",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
# INSCRIPTIONS
op.drop_constraint(
"notes_formsemestre_inscription_etudid_fkey",
"notes_formsemestre_inscription",
type_="foreignkey",
)
op.create_foreign_key(
"notes_formsemestre_inscription_etudid_fkey",
"notes_formsemestre_inscription",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
op.add_column(
"notes_formsemestre_inscription",
sa.Column("parcour_id", sa.Integer(), nullable=True),
)
op.create_index(
op.f("ix_notes_formsemestre_inscription_parcour_id"),
"notes_formsemestre_inscription",
["parcour_id"],
unique=False,
)
op.create_foreign_key(
"notes_formsemestre_inscription_parcour_id_fkey",
"notes_formsemestre_inscription",
"apc_parcours",
["parcour_id"],
["id"],
)
# ---
op.drop_constraint("notes_notes_etudid_fkey", "notes_notes", type_="foreignkey")
op.create_foreign_key(
"notes_notes_etudid_fkey",
"notes_notes",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint(
"notes_notes_log_etudid_fkey", "notes_notes_log", type_="foreignkey"
)
op.create_foreign_key(
"notes_notes_log_etudid_fkey",
"notes_notes_log",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint(
"scolar_autorisation_inscription_etudid_fkey",
"scolar_autorisation_inscription",
type_="foreignkey",
)
op.create_foreign_key(
"scolar_autorisation_inscription_etudid_fkey",
"scolar_autorisation_inscription",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint("scolar_events_etudid_fkey", "scolar_events", type_="foreignkey")
op.create_foreign_key(
"scolar_events_etudid_fkey",
"scolar_events",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint(
"scolar_formsemestre_validation_etudid_fkey",
"scolar_formsemestre_validation",
type_="foreignkey",
)
op.create_foreign_key(
"scolar_formsemestre_validation_etudid_fkey",
"scolar_formsemestre_validation",
"identite",
["etudid"],
["id"],
ondelete="CASCADE",
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(
"scolar_formsemestre_validation_etudid_fkey",
"scolar_formsemestre_validation",
type_="foreignkey",
)
op.create_foreign_key(
"scolar_formsemestre_validation_etudid_fkey",
"scolar_formsemestre_validation",
"identite",
["etudid"],
["id"],
)
op.drop_constraint("scolar_events_etudid_fkey", "scolar_events", type_="foreignkey")
op.create_foreign_key(
"scolar_events_etudid_fkey", "scolar_events", "identite", ["etudid"], ["id"]
)
op.drop_constraint(
"scolar_autorisation_inscription_etudid_fkey",
"scolar_autorisation_inscription",
type_="foreignkey",
)
op.create_foreign_key(
"scolar_autorisation_inscription_etudid_fkey",
"scolar_autorisation_inscription",
"identite",
["etudid"],
["id"],
)
op.drop_constraint(
"notes_notes_log_etudid_fkey", "notes_notes_log", type_="foreignkey"
)
op.create_foreign_key(
"notes_notes_log_etudid_fkey", "notes_notes_log", "identite", ["etudid"], ["id"]
)
op.drop_constraint("notes_notes_etudid_fkey", "notes_notes", type_="foreignkey")
op.create_foreign_key(
"notes_notes_etudid_fkey", "notes_notes", "identite", ["etudid"], ["id"]
)
# INSCRIPTIONS
op.drop_constraint(
"notes_formsemestre_inscription_etudid_fkey",
"notes_formsemestre_inscription",
type_="foreignkey",
)
op.create_foreign_key(
"notes_formsemestre_inscription_etudid_fkey",
"notes_formsemestre_inscription",
"identite",
["etudid"],
["id"],
)
op.drop_constraint(
"notes_formsemestre_inscription_parcour_id_fkey",
"notes_formsemestre_inscription",
type_="foreignkey",
)
op.drop_index(
op.f("ix_notes_formsemestre_inscription_parcour_id"),
table_name="notes_formsemestre_inscription",
)
op.drop_column("notes_formsemestre_inscription", "parcour_id")
# --
op.drop_constraint(
"notes_appreciations_etudid_fkey", "notes_appreciations", type_="foreignkey"
)
op.create_foreign_key(
"notes_appreciations_etudid_fkey",
"notes_appreciations",
"identite",
["etudid"],
["id"],
)
op.drop_constraint("itemsuivi_etudid_fkey", "itemsuivi", type_="foreignkey")
op.create_foreign_key(
"itemsuivi_etudid_fkey", "itemsuivi", "identite", ["etudid"], ["id"]
)
op.drop_constraint(
"group_membership_etudid_fkey", "group_membership", type_="foreignkey"
)
op.create_foreign_key(
"group_membership_etudid_fkey",
"group_membership",
"identite",
["etudid"],
["id"],
)
op.drop_constraint("adresse_etudid_fkey", "adresse", type_="foreignkey")
op.create_foreign_key(
"adresse_etudid_fkey", "adresse", "identite", ["etudid"], ["id"]
)
op.drop_constraint("admissions_etudid_fkey", "admissions", type_="foreignkey")
op.create_foreign_key(
"admissions_etudid_fkey", "admissions", "identite", ["etudid"], ["id"]
)
op.drop_constraint(
"absences_notifications_etudid_fkey",
"absences_notifications",
type_="foreignkey",
)
op.create_foreign_key(
"absences_notifications_etudid_fkey",
"absences_notifications",
"identite",
["etudid"],
["id"],
)
op.drop_constraint("absences_etudid_fkey", "absences", type_="foreignkey")
op.create_foreign_key(
"absences_etudid_fkey", "absences", "identite", ["etudid"], ["id"]
)
op.drop_table("parcours_formsemestre")
# ### end Alembic commands ###

View File

@ -14,6 +14,7 @@ Au besoin, créer un base de test neuve:
import random import random
from flask import g from flask import g
from app.models.formsemestre import FormSemestreInscription
from config import TestConfig from config import TestConfig
from tests.unit import sco_fake_gen from tests.unit import sco_fake_gen
@ -85,6 +86,15 @@ def run_sco_basic(verbose=False):
# --- Inscription des étudiants # --- Inscription des étudiants
for etud in etuds: for etud in etuds:
G.inscrit_etudiant(formsemestre_id, etud) G.inscrit_etudiant(formsemestre_id, etud)
# Vérification incription semestre:
q = FormSemestreInscription.query.filter_by(
etudid=etuds[0].id, formsemestre_id=formsemestre_id
)
assert q.count() == 1
ins = q.first()
assert ins.etape == None
assert ins.etat == "I"
assert ins.parcour == None
# --- Creation évaluation # --- Creation évaluation
e = G.create_evaluation( e = G.create_evaluation(
@ -217,3 +227,15 @@ def run_sco_basic(verbose=False):
dec_ues = nt.get_etud_decision_ues(etud["etudid"]) dec_ues = nt.get_etud_decision_ues(etud["etudid"])
for ue_id in dec_ues: for ue_id in dec_ues:
assert dec_ues[ue_id]["code"] in {"ADM", "CMP"} assert dec_ues[ue_id]["code"] in {"ADM", "CMP"}
# ---- Suppression étudiant, vérification inscription
# (permet de tester les cascades)
etud = etuds[0]
etudid = etud.id
db.session.delete(etud)
db.session.commit()
# Vérification incription semestre:
q = FormSemestreInscription.query.filter_by(
etudid=etudid, formsemestre_id=formsemestre_id
)
assert q.count() == 0