"""
+
+ def html(self) -> str:
+ "Affichage html"
+ date_str = (
+ f"""le {self.date.strftime(scu.DATEATIME_FMT)}"""
+ if self.date
+ else "(sans date)"
+ )
+ link = (
+ self.formsemestre.html_link_status(
+ label=f"{self.formsemestre.titre_formation(with_sem_idx=1)}",
+ title=self.formsemestre.titre_annee(),
+ )
+ if self.formsemestre
+ else "externe/antérieure"
+ )
+ specialite = (
+ self.formsemestre.formation.referentiel_competence.get_title()
+ if self.formsemestre.formation.referentiel_competence
+ else "(désassociée!)"
+ )
+ return f"""Diplôme de DUT en 120 ECTS du {specialite} émis par
+ {link}
+ {date_str}
+ """
diff --git a/app/models/etudiants.py b/app/models/etudiants.py
index 946b4f661..55a11dccf 100644
--- a/app/models/etudiants.py
+++ b/app/models/etudiants.py
@@ -179,7 +179,9 @@ class Identite(models.ScoDocModel):
def html_link_fiche(self) -> str:
"lien vers la fiche"
- return f"""{self.nomprenom} """
+ return (
+ f"""{self.nom_prenom()} """
+ )
def url_fiche(self) -> str:
"url de la fiche étudiant"
@@ -314,7 +316,7 @@ class Identite(models.ScoDocModel):
@property
def nomprenom(self, reverse=False) -> str:
- """DEPRECATED
+ """DEPRECATED: préférer nom_prenom()
Civilité/prénom/nom pour affichages: "M. Pierre Dupont"
Si reverse, "Dupont Pierre", sans civilité.
Prend l'identité courante et non celle de l'état civil si elles diffèrent.
diff --git a/app/scodoc/sco_page_etud.py b/app/scodoc/sco_page_etud.py
index 94abc5ed4..0177cf483 100644
--- a/app/scodoc/sco_page_etud.py
+++ b/app/scodoc/sco_page_etud.py
@@ -37,7 +37,14 @@ import sqlalchemy as sa
from app import log
from app.auth.models import User
from app.but import cursus_but, validations_view
-from app.models import Adresse, EtudAnnotation, FormSemestre, Identite, ScoDocSiteConfig
+from app.models import (
+ Adresse,
+ EtudAnnotation,
+ FormSemestre,
+ Identite,
+ ScoDocSiteConfig,
+ ValidationDUT120,
+)
from app.scodoc import (
codes_cursus,
html_sco_header,
@@ -455,6 +462,20 @@ def fiche_etud(etudid=None):
ects_total = sum((v.ects() for v in ue_validation_by_niveau.values()))
else:
ects_total = ""
+
+ validation_dut120 = ValidationDUT120.query.filter_by(etudid=etudid).first()
+ validation_dut120_html = (
+ f"""Diplôme DUT décerné
+ en S{validation_dut120.formsemestre.semestre_id}
+ """
+ if validation_dut120
+ else ""
+ )
+
info[
"but_cursus_mkup"
] = f"""
@@ -463,6 +484,7 @@ def fiche_etud(etudid=None):
"but/cursus_etud.j2",
cursus=but_cursus,
scu=scu,
+ validation_dut120_html=validation_dut120_html,
)}
@@ -471,7 +493,7 @@ def fiche_etud(etudid=None):
formsemestre_id=last_formsemestre.id)}"
title="Visualiser les compétences BUT"
>
-
+
Compétences BUT
diff --git a/app/static/css/cursus_but.css b/app/static/css/cursus_but.css
index 83438d250..340b8ff2a 100644
--- a/app/static/css/cursus_but.css
+++ b/app/static/css/cursus_but.css
@@ -40,6 +40,25 @@ div.code_rcue {
position: relative;
}
+div.cursus_but .validation_dut120 {
+ grid-column: span 3;
+ justify-self: end;
+ /* align on right of BUT2 */
+ width: auto;
+ /* fit its content */
+ text-align: center;
+ padding: 6px;
+ font-weight: bold;
+ color: rgb(0, 0, 192);
+ background-color: #eee;
+ border-radius: 8px;
+ border: 1px solid rgb(0, 0, 192);
+}
+
+div.validation_dut120 a.stdlink {
+ color: rgb(0, 0, 192);
+}
+
div.no_niveau {
background-color: rgb(245, 237, 200);
}
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index 815c12515..b3cc3d967 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -959,7 +959,7 @@ td.fichetitre2 .fl {
div.section_but {
display: flex;
flex-direction: row;
- align-items: flex-end;
+ align-items: center;
justify-content: space-evenly;
}
@@ -974,7 +974,8 @@ div.fiche_total_etcs {
margin-top: 16px;
}
-div.section_but>div.link_validation_rcues {
+div.section_but div.link_validation_rcues,
+div.section_but div.link_validation_rcues img {
align-self: center;
text-align: center;
}
@@ -4590,6 +4591,10 @@ table.table_recap tr td.jury_code_sem {
border-left: 1px solid blue;
}
+table.table_recap tr td.col_jury_link {
+ border-left: 1px solid blue;
+}
+
table.table_recap .admission {
white-space: nowrap;
color: rgb(6, 73, 6);
diff --git a/app/tables/jury_recap.py b/app/tables/jury_recap.py
index 2cb25ede4..8c538ad66 100644
--- a/app/tables/jury_recap.py
+++ b/app/tables/jury_recap.py
@@ -18,7 +18,7 @@ from app.but import jury_but
from app.but.jury_but import DecisionsProposeesRCUE
from app.comp.res_compat import NotesTableCompat
-from app.models import ApcNiveau, UniteEns
+from app.models import ApcNiveau, UniteEns, ValidationDUT120
from app.models.etudiants import Identite
from app.scodoc.codes_cursus import (
BUT_BARRE_RCUE,
@@ -149,7 +149,7 @@ class TableJury(TableRecap):
"ects_acquis",
"ECTS",
# res.get_etud_ects_valides(etud.id),
- # cette recherche augmente de 10% le temps de contsruction de la table
+ # cette recherche augmente de 10% le temps de construction de la table
cursus_but.but_ects_valides(
etud, res.formsemestre.formation.referentiel_competence_id
),
@@ -157,6 +157,16 @@ class TableJury(TableRecap):
classes=["recorded_code"],
target_attrs={"title": "crédits validés en BUT"},
)
+ # Diplôme DUT120
+ validation_dut120 = ValidationDUT120.query.filter_by(etudid=etud.id).first()
+ if validation_dut120:
+ row.add_cell(
+ "dut120",
+ "DUT",
+ "DUT",
+ group="jury_code_sem",
+ classes=["recorded_code"],
+ )
# Lien saisie ou visu jury
a_saisir = (not res.validations) or (not res.validations.has_decision(etud))
row.add_cell(
diff --git a/app/templates/but/cursus_etud.j2 b/app/templates/but/cursus_etud.j2
index 0a0782d6d..45330b185 100644
--- a/app/templates/but/cursus_etud.j2
+++ b/app/templates/but/cursus_etud.j2
@@ -30,4 +30,10 @@
{% endfor %}
{% endfor %}
+ {% if validation_dut120_html %}
+
+ {{validation_dut120_html | safe }}
+
+ {% endif %}
\ No newline at end of file
diff --git a/app/templates/but/validate_dut120.j2 b/app/templates/but/validate_dut120.j2
new file mode 100644
index 000000000..3cfe91899
--- /dev/null
+++ b/app/templates/but/validate_dut120.j2
@@ -0,0 +1,68 @@
+{% extends "sco_page.j2" %}
+
+{% block styles %}
+ {{super()}}
+
+{% endblock %}
+
+
+{% block app_content %}
+
+
+
+
Validation du DUT en 120 ECTS dans un parcours BUT
+
{{etud.html_link_fiche()|safe}}
+
+
+
+
+
+
Les étudiants de BUT peuvent demander l’attribution du diplôme universitaire de technologie
+(DUT) au terme de l’acquisition des 120 premiers crédits européens du cursus.
+
+
Dans ScoDoc, c'est le référentiel de compétence qui détermine la spécialité (si un étudiant redouble dans
+une formation utilisant une autre version de référentiel, pensez à revalider ses UEs).
+
+
+
+
+ {{etud.html_link_fiche()|safe}} a acquis {{ects_but1_but2}} ECTS en BUT1 et BUT2.
+ {% if not validation %}
+ Son DUT n'est pas encore enregistré dans cette spécialité.
+ {% endif %}
+
+
+{% if etud_can_validate_dut %}
+
+{% else %}
+
+ {% if validation %}
+ DUT déjà validé dans cette spécialité
+
{{formsemestre.formation.referentiel_competence.get_title()}}
+ pour l'étudiant{{etud.ne}} {{etud.html_link_fiche()|safe}}
+
+ DUT 120 spécialité {{formsemestre.formation.referentiel_competence.specialite_long}}
+ enregistré le {{time.strftime("%d/%m/%Y à %Hh%M")}}
+
+
+
+ {% else %}
+ L'étudiant ne satisfait pas les conditions :
+ vérifiez qu'il a validé et enregistré ses UEs de BUT1 et BUT2
+ et ainsi acquis 120 crédits ECTS.
+ Voir la page
compétences BUT .
+
+ {% endif %}
+{% endif %}
+{% endblock %}
diff --git a/app/templates/jury/jury_delete_manual.j2 b/app/templates/jury/jury_delete_manual.j2
index 3c53faed1..7eef80724 100644
--- a/app/templates/jury/jury_delete_manual.j2
+++ b/app/templates/jury/jury_delete_manual.j2
@@ -84,6 +84,22 @@ pages de saisie de jury habituelles).
{% endif %}
+{% if dut120_vals.count() %}
+
+
Diplôme de DUT en 120 ECTS (dans un parcours BUT)
+
+ {% for v in dut120_vals %}
+ {{v.html()|safe}}
+
+
+ {% endfor %}
+
+
+{% endif %}
+
{% if autorisations.first() %}
Autorisations d'inscriptions (passages)
@@ -140,6 +156,7 @@ document.addEventListener('DOMContentLoaded', () => {
if (response.ok) {
location.reload();
} else {
+ console.log(`Error: ${SCO_URL}../api/etudiant/${etudid}/jury/${validation_type}/${v_id}/delete`);
throw new Error('Request failed');
}
});
diff --git a/app/views/notes.py b/app/views/notes.py
index 9ab4e1999..9157af762 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -53,7 +53,7 @@ from app.but import (
jury_but_view,
)
from app.but import bulletin_but_court # ne pas enlever: ajoute des routes !
-
+from app.but import jury_dut120 # ne pas enlever: ajoute des routes !
from app.but.forms import jury_but_forms
@@ -2568,6 +2568,13 @@ def formsemestre_validation_but(
scodoc_dept=g.scodoc_dept,
etudid=deca.etud.id, formsemestre_id=formsemestre_id)}"
>enregistrer des UEs antérieures
+
+
décerner le DUT "120ECTS"
"""
H.append(
f"""
diff --git a/migrations/versions/9794534db935_validationdut120.py b/migrations/versions/9794534db935_validationdut120.py
new file mode 100644
index 000000000..9273bc310
--- /dev/null
+++ b/migrations/versions/9794534db935_validationdut120.py
@@ -0,0 +1,58 @@
+"""ValidationDUT120
+
+Revision ID: 9794534db935
+Revises: 60119446aab6
+Create Date: 2024-07-06 17:36:41.576748
+
+"""
+
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = "9794534db935"
+down_revision = "60119446aab6"
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ op.create_table(
+ "validation_dut120",
+ sa.Column("id", sa.Integer(), nullable=False),
+ sa.Column("etudid", sa.Integer(), nullable=False),
+ sa.Column("formsemestre_id", sa.Integer(), nullable=False),
+ sa.Column("referentiel_competence_id", sa.Integer(), nullable=False),
+ sa.Column(
+ "date",
+ sa.DateTime(timezone=True),
+ server_default=sa.text("now()"),
+ nullable=False,
+ ),
+ sa.ForeignKeyConstraint(["etudid"], ["identite.id"], ondelete="CASCADE"),
+ sa.ForeignKeyConstraint(
+ ["formsemestre_id"],
+ ["notes_formsemestre.id"],
+ ondelete="CASCADE",
+ ),
+ sa.ForeignKeyConstraint(
+ ["referentiel_competence_id"],
+ ["apc_referentiel_competences.id"],
+ ),
+ sa.PrimaryKeyConstraint("id"),
+ )
+ with op.batch_alter_table("validation_dut120", schema=None) as batch_op:
+ batch_op.create_index(
+ batch_op.f("ix_validation_dut120_etudid"), ["etudid"], unique=False
+ )
+
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ with op.batch_alter_table("validation_dut120", schema=None) as batch_op:
+ batch_op.drop_index(batch_op.f("ix_validation_dut120_etudid"))
+
+ op.drop_table("validation_dut120")
+ # ### end Alembic commands ###