diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py index 481393c5ef..eb71373f15 100644 --- a/app/but/bulletin_but.py +++ b/app/but/bulletin_but.py @@ -484,6 +484,7 @@ class BulletinBUT: d["etudid"] = etud.id d["etud"] = d["etudiant"] d["etud"]["nomprenom"] = etud.nomprenom + d["etud"]["etat_civil"] = etud.etat_civil d.update(self.res.sem) etud_etat = self.res.get_etud_etat(etud.id) d["filigranne"] = sco_bulletins_pdf.get_filigranne( diff --git a/app/models/etudiants.py b/app/models/etudiants.py index e4b2e5bbb9..fb98e98b1c 100644 --- a/app/models/etudiants.py +++ b/app/models/etudiants.py @@ -30,6 +30,7 @@ class Identite(db.Model): db.UniqueConstraint("dept_id", "code_nip"), db.UniqueConstraint("dept_id", "code_ine"), db.CheckConstraint("civilite IN ('M', 'F', 'X')"), + db.CheckConstraint("civilite_etat_civil IN ('M', 'F', 'X')"), ) id = db.Column(db.Integer, primary_key=True) @@ -41,6 +42,12 @@ class Identite(db.Model): nom_usuel = db.Column(db.Text()) "optionnel (si present, affiché à la place du nom)" civilite = db.Column(db.String(1), nullable=False) + + # données d'état-civil. Si présent remplace les données d'usage dans les documents officiels (bulletins, PV) + # cf nomprenom_etat_civil() + civilite_etat_civil = db.Column(db.String(1), nullable=False, server_default="X") + prenom_etat_civil = db.Column(db.Text(), nullable=True) + date_naissance = db.Column(db.Date) lieu_naissance = db.Column(db.Text()) dept_naissance = db.Column(db.Text()) @@ -104,6 +111,13 @@ class Identite(db.Model): """ return {"M": "M.", "F": "Mme", "X": ""}[self.civilite] + @property + def civilite_etat_civil_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_etat_civil] + def sex_nom(self, no_accents=False) -> str: "'M. DUPONTÉ', ou si no_accents, 'M. DUPONTE'" s = f"{self.civilite_str} {(self.nom_usuel or self.nom).upper()}" @@ -150,6 +164,14 @@ class Identite(db.Model): r.append("-".join([x.lower().capitalize() for x in fields])) return " ".join(r) + @property + def etat_civil(self): + if self.prenom_etat_civil: + civ = {"M": "M.", "F": "Mme", "X": ""}[self.civilite_etat_civil] + return f"{civ} {self.prenom_etat_civil} {self.nom}" + else: + return self.nomprenom + @property def nom_short(self): "Nom et début du prénom pour table recap: 'DUPONT Pi.'" @@ -191,6 +213,8 @@ class Identite(db.Model): "nom_usuel": self.nom_usuel, "prenom": self.prenom, "sort_key": self.sort_key, + "civilite_etat_civil": self.civilite_etat_civil, + "prenom_etat_civil": self.prenom_etat_civil, } def to_dict_scodoc7(self) -> dict: @@ -234,6 +258,8 @@ class Identite(db.Model): "dept_naissance": self.dept_naissance or "", "nationalite": self.nationalite or "", "boursier": self.boursier or "", + "civilite_etat_civil": self.civilite_etat_civil, + "prenom_etat_civil": self.prenom_etat_civil, } if include_urls and has_request_context(): # test request context so we can use this func in tests under the flask shell @@ -450,10 +476,10 @@ class Identite(db.Model): M. Pierre Dupont """ if with_paragraph: - return f"""{self.nomprenom}{line_sep}n°{self.code_nip or ""}{line_sep}né{self.e} le { + return f"""{self.etat_civil}{line_sep}n°{self.code_nip or ""}{line_sep}né{self.e} le { self.date_naissance.strftime("%d/%m/%Y") if self.date_naissance else ""}{ line_sep}à {self.lieu_naissance or ""}""" - return self.nomprenom + return self.etat_civil def photo_html(self, title=None, size="small") -> str: """HTML img tag for the photo, either in small size (h90) diff --git a/app/scodoc/sco_bulletins_generator.py b/app/scodoc/sco_bulletins_generator.py index ec5d258a7a..b122d7a46b 100644 --- a/app/scodoc/sco_bulletins_generator.py +++ b/app/scodoc/sco_bulletins_generator.py @@ -167,8 +167,9 @@ class BulletinGenerator: formsemestre_id = self.bul_dict["formsemestre_id"] nomprenom = self.bul_dict["etud"]["nomprenom"] + etat_civil = self.bul_dict["etud"]["etat_civil"] marque_debut_bulletin = sco_pdf.DebutBulletin( - nomprenom, + self.bul_dict["etat_civil"], filigranne=self.bul_dict["filigranne"], footer_content=f"""ScoDoc - Bulletin de {nomprenom} - {time.strftime("%d/%m/%Y %H:%M")}""", ) @@ -211,7 +212,7 @@ class BulletinGenerator: document, author="%s %s (E. Viennet) [%s]" % (sco_version.SCONAME, sco_version.SCOVERSION, self.description), - title=f"""Bulletin {sem["titremois"]} de {nomprenom}""", + title=f"""Bulletin {sem["titremois"]} de {etat_civil}""", subject="Bulletin de note", margins=self.margins, server_name=self.server_name, diff --git a/app/scodoc/sco_etud.py b/app/scodoc/sco_etud.py index 5a2313fae1..70b7b16366 100644 --- a/app/scodoc/sco_etud.py +++ b/app/scodoc/sco_etud.py @@ -57,7 +57,12 @@ def format_etud_ident(etud): else: etud["nom_usuel"] = "" etud["prenom"] = format_prenom(etud["prenom"]) + if "prenom_etat_civil" in etud: + etud["prenom_etat_civil"] = format_prenom(etud["prenom_etat_civil"]) + else: + etud["prenom_etat_civil"] = "" etud["civilite_str"] = format_civilite(etud["civilite"]) + etud["civilite_etat_civil_str"] = format_civilite(etud["civilite_etat_civil"]) # Nom à afficher: if etud["nom_usuel"]: etud["nom_disp"] = etud["nom_usuel"] @@ -225,7 +230,12 @@ _identiteEditor = ndb.EditableTable( "nom", "nom_usuel", "prenom", + "prenom_etat_civil", + "cas_id", + "cas_allow_login", + "cas_allow_scodoc_login", "civilite", # 'M", "F", or "X" + "civilite_etat_civil", "date_naissance", "lieu_naissance", "dept_naissance", @@ -242,7 +252,9 @@ _identiteEditor = ndb.EditableTable( input_formators={ "nom": force_uppercase, "prenom": force_uppercase, + "prenom_etat_civil": force_uppercase, "civilite": input_civilite, + "civilite_etat_civil": input_civilite, "date_naissance": ndb.DateDMYtoISO, "boursier": bool, }, @@ -263,6 +275,7 @@ def identite_list(cnx, *a, **kw): else: o["annee_naissance"] = o["date_naissance"] o["civilite_str"] = format_civilite(o["civilite"]) + o["civilite_etat_civil_str"] = format_civilite(o["civilite_etat_civil"]) return objs diff --git a/app/scodoc/sco_import_etuds.py b/app/scodoc/sco_import_etuds.py index 110d95d889..2d67c08cde 100644 --- a/app/scodoc/sco_import_etuds.py +++ b/app/scodoc/sco_import_etuds.py @@ -71,6 +71,8 @@ FORMAT_FILE = "format_import_etudiants.txt" ADMISSION_MODIFIABLE_FIELDS = ( "code_nip", "code_ine", + "prenom_etat_civil", + "civilite_etat_civil", "date_naissance", "lieu_naissance", "bac", diff --git a/app/scodoc/sco_page_etud.py b/app/scodoc/sco_page_etud.py index 6ac2b4bc0d..b6a3592d67 100644 --- a/app/scodoc/sco_page_etud.py +++ b/app/scodoc/sco_page_etud.py @@ -176,6 +176,18 @@ def ficheEtud(etudid=None): sco_etud.fill_etuds_info([etud_]) # info = etud_ + if etud.prenom_etat_civil: + info["etat_civil"] = ( + "
%(nomprenom)s (%(inscription)s)- +%(etat_civil)s %(emaillink)s | %(etudfoto)s diff --git a/app/views/scolar.py b/app/views/scolar.py index 6268c7e20b..3a4e89d355 100644 --- a/app/views/scolar.py +++ b/app/views/scolar.py @@ -557,6 +557,7 @@ def etud_info(etudid=None, format="xml"): "nom_usuel", "prenom", "nomprenom", + "prenom_etat_civil", "email", "emailperso", "domicile", @@ -577,6 +578,9 @@ def etud_info(etudid=None, format="xml"): ): d[a] = etud[a] # ne pas quoter car ElementTree.tostring quote déjà d["civilite"] = etud["civilite_str"] # exception: ne sort pas la civilite brute + d["civilite_etat_civil"] = etud[ + "civilite_etat_civil_str" + ] # exception: ne sort pas la civilite brute d["sexe"] = d["civilite"] # backward compat pour anciens clients d["photo_url"] = sco_photos.etud_photo_url(etud) @@ -1442,6 +1446,25 @@ def _etudident_create_or_edit_form(edit): "title": "Civilité", }, ), + ( + "prenom_etat_civil", + { + "size": 25, + "title": "Prénom (état-civil)", + "allow_null": True, + "explanation": "Si précisé, remplace le prénom d'usage dans les documents officiels", + }, + ), + ( + "civilite_etat_civil", + { + "input_type": "menu", + "labels": ["Homme", "Femme", "Autre/neutre"], + "allowed_values": ["M", "F", "X"], + "title": "Civilité (état-civil)", + "explanation": "Si précisé: remplace la civilité d'usage dans les documents officiels", + }, + ), ( "date_naissance", { diff --git a/migrations/versions/cf29790ca6f6_ajout_prenom_civilite__etat_civil.py b/migrations/versions/cf29790ca6f6_ajout_prenom_civilite__etat_civil.py new file mode 100644 index 0000000000..8b13136ad3 --- /dev/null +++ b/migrations/versions/cf29790ca6f6_ajout_prenom_civilite__etat_civil.py @@ -0,0 +1,33 @@ +"""ajout (prenom,civilite)_etat_civil + +Revision ID: cf29790ca6f6 +Revises: 6520faf67508 +Create Date: 2023-02-25 10:55:42.831526 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "cf29790ca6f6" +down_revision = "6520faf67508" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - checked ### + op.add_column( + "identite", + sa.Column("civilite_etat_civil", sa.Text(), nullable=True, server_default="X"), + ) + op.add_column("identite", sa.Column("prenom_etat_civil", sa.Text(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - checked ### + op.drop_column("identite", "prenom_etat_civil") + op.drop_column("identite", "civilite_etat_civil") + # ### end Alembic commands ### diff --git a/tools/format_import_etudiants.txt b/tools/format_import_etudiants.txt index 3ba04f50bb..ad18c2750f 100644 --- a/tools/format_import_etudiants.txt +++ b/tools/format_import_etudiants.txt @@ -9,6 +9,8 @@ nom; text; identite; 0; nom de l'etudiant; nom_usuel; text; identite; 1; nom usuel (si different); prenom; text; identite; 0; prenom de l'etudiant civilite; text; identite; 1; sexe ('M', 'F', 'X');sexe;genre +prenom_etat_civil; text; identite; 1; prenom à l'état-civil (si différent);prenom_etat_civil +civilite_etat_civil; text; identite; 1; sexe ('M', 'F', 'X') à l'état civil;civilite_etat_civil date_naissance;text;identite; 1; date de naissance (jj/mm/aaaa) lieu_naissance;text;identite; 1; lieu de naissance nationalite; text; identite; 1; nationalite |