diff --git a/app/models/etudiants.py b/app/models/etudiants.py
index 77d07250ae..9cfc56a430 100644
--- a/app/models/etudiants.py
+++ b/app/models/etudiants.py
@@ -27,6 +27,7 @@ class Identite(db.Model):
__table_args__ = (
db.UniqueConstraint("dept_id", "code_nip"),
db.UniqueConstraint("dept_id", "code_ine"),
+ db.CheckConstraint("civilite IN ('M', 'F', 'X')"),
)
id = db.Column(db.Integer, primary_key=True)
@@ -36,10 +37,8 @@ class Identite(db.Model):
nom = db.Column(db.Text())
prenom = db.Column(db.Text())
nom_usuel = db.Column(db.Text())
- # optionnel (si present, affiché à la place du nom)
+ "optionnel (si present, affiché à la place du nom)"
civilite = db.Column(db.String(1), nullable=False)
- __table_args__ = (db.CheckConstraint("civilite IN ('M', 'F', 'X')"),)
-
date_naissance = db.Column(db.Date)
lieu_naissance = db.Column(db.Text())
dept_naissance = db.Column(db.Text())
diff --git a/app/scodoc/sco_etud.py b/app/scodoc/sco_etud.py
index 3960286823..4b2f5e887c 100644
--- a/app/scodoc/sco_etud.py
+++ b/app/scodoc/sco_etud.py
@@ -301,24 +301,27 @@ def check_nom_prenom(cnx, nom="", prenom="", etudid=None):
def _check_duplicate_code(cnx, args, code_name, disable_notify=False, edit=True):
+ """Vérifie que le code n'est pas dupliqué"""
etudid = args.get("etudid", None)
if args.get(code_name, None):
etuds = identite_list(cnx, {code_name: str(args[code_name])})
- # log('etuds=%s'%etuds)
- nb_max = 0
+ duplicate = False
if edit:
- nb_max = 1
- if len(etuds) > nb_max:
+ duplicate = (len(etuds) > 1) or (
+ (len(etuds) == 1) and etuds[0]["id"] != args["etudid"]
+ )
+ else:
+ duplicate = len(etuds) > 0
+ if duplicate:
listh = [] # liste des doubles
for e in etuds:
listh.append(
- """Autre étudiant: """
- % url_for(
- "scolar.ficheEtud",
- scodoc_dept=g.scodoc_dept,
- etudid=e["etudid"],
- )
- + """%(nom)s %(prenom)s""" % e
+ f"""Autre étudiant: {e['nom']} {e['prenom']}"""
)
if etudid:
OK = "retour à la fiche étudiant"
@@ -349,7 +352,7 @@ def _check_duplicate_code(cnx, args, code_name, disable_notify=False, edit=True)
"""
else:
err_page = f"""
Code étudiant ({code_name}) dupliqué !
"""
- log("*** error: code %s duplique: %s" % (code_name, args[code_name]))
+ log(f"*** error: code {code_name} duplique: {args[code_name]}")
raise ScoGenError(err_page)
diff --git a/app/views/scolar.py b/app/views/scolar.py
index 620066169f..38c33ae81b 100644
--- a/app/views/scolar.py
+++ b/app/views/scolar.py
@@ -1732,7 +1732,9 @@ def _etudident_create_or_edit_form(edit):
formsemestre_id=formsemestre_id
) # > etudident_create_or_edit
#
- return flask.redirect("ficheEtud?etudid=" + str(etudid))
+ return flask.redirect(
+ url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
+ )
@bp.route("/etudident_delete", methods=["GET", "POST"])
diff --git a/migrations/versions/ae9bb0feea7a_contraintes_identite.py b/migrations/versions/ae9bb0feea7a_contraintes_identite.py
new file mode 100644
index 0000000000..4688f92ff4
--- /dev/null
+++ b/migrations/versions/ae9bb0feea7a_contraintes_identite.py
@@ -0,0 +1,97 @@
+"""contraintes identite
+
+Revision ID: ae9bb0feea7a
+Revises: 5731e904baac
+Create Date: 2023-03-12 19:00:58.544873
+
+"""
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.orm import sessionmaker # added by ev
+
+
+# revision identifiers, used by Alembic.
+revision = "ae9bb0feea7a"
+down_revision = "5731e904baac"
+branch_labels = None
+depends_on = None
+
+Session = sessionmaker()
+
+
+def upgrade():
+ # On répare une erreur (typo) dans la déclaration de la table Identite
+ # qui faisait que les contraintes d'unicité des couples (ine, dept)
+ # et (nip, dept) n'était pas prises en compte.
+ # On commence par chercher les éventuels (rares) doublons, changer leurs codes
+ # avant de créer les contraintes.
+ bind = op.get_bind()
+ session = Session(bind=bind)
+ # Corrige NIP
+ dups = session.execute(
+ """SELECT dept_id, code_nip
+ FROM identite
+ WHERE code_nip IS NOT NULL
+ GROUP BY dept_id, code_nip
+ HAVING COUNT(*) > 1;"""
+ ).all()
+ for dept_id, code_nip in dups:
+ etuds_dups = session.execute(
+ """SELECT id, nom, prenom FROM identite
+ WHERE code_nip=:code_nip""",
+ {"code_nip": code_nip},
+ ).all()
+ for i, (etudid, nom, prenom) in enumerate(etuds_dups[1:], start=1):
+ session.execute(
+ """UPDATE identite SET code_nip=:code_nip WHERE id=:etudid""",
+ {
+ "code_nip": f"{code_nip}-{i}",
+ "etudid": etudid,
+ },
+ )
+ print(
+ f"Warning: duplication de code NIP détectée: vérifier {nom} {prenom} NIP={code_nip}"
+ )
+ session.commit()
+ # Corrige INE
+ dups = session.execute(
+ """SELECT dept_id, code_ine
+ FROM identite
+ WHERE code_ine IS NOT NULL
+ GROUP BY dept_id, code_ine
+ HAVING COUNT(*) > 1;"""
+ ).all()
+ for dept_id, code_ine in dups:
+ etuds_dups = session.execute(
+ """SELECT id, nom, prenom FROM identite
+ WHERE code_ine=:code_ine""",
+ {"code_ine": code_ine},
+ ).all()
+ for i, (etudid, nom, prenom) in enumerate(etuds_dups[1:], start=1):
+ session.execute(
+ """UPDATE identite SET code_ine=:code_ine WHERE id=:etudid""",
+ {
+ "code_ine": f"{code_ine}-{i}",
+ "etudid": etudid,
+ },
+ )
+ print(
+ f"Warning: duplication de code INE détectée: vérifier {nom} {prenom} NIP={code_ine}"
+ )
+ session.commit()
+
+ # CREATION DES CONTRAINTES
+ op.create_unique_constraint(
+ "identite_dept_id_code_nip_key", "identite", ["dept_id", "code_nip"]
+ )
+ op.create_unique_constraint(
+ "identite_dept_id_code_ine_key", "identite", ["dept_id", "code_ine"]
+ )
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_constraint("identite_dept_id_code_nip_key", "identite", type_="unique")
+ op.drop_constraint("identite_dept_id_code_ine_key", "identite", type_="unique")
+ # ### end Alembic commands ###