diff --git a/app/models/but_validations.py b/app/models/but_validations.py
index 4054c9f43b..00dc61952f 100644
--- a/app/models/but_validations.py
+++ b/app/models/but_validations.py
@@ -4,7 +4,6 @@
"""
from typing import Union
-from flask_sqlalchemy.query import Query
from app import db
from app.models import CODE_STR_LEN
@@ -13,8 +12,6 @@ from app.models.etudiants import Identite
from app.models.formations import Formation
from app.models.formsemestre import FormSemestre
from app.models.ues import UniteEns
-from app.scodoc import codes_cursus as sco_codes
-from app.scodoc import sco_utils as scu
class ApcValidationRCUE(db.Model):
@@ -22,7 +19,7 @@ class ApcValidationRCUE(db.Model):
aka "regroupements cohérents d'UE" dans le jargon BUT.
- Le formsemestre est celui du semestre PAIR du niveau de compétence
+ Le formsemestre est l'origine, utilisé pour effacer
"""
__tablename__ = "apc_validation_rcue"
@@ -109,139 +106,6 @@ class ApcValidationRCUE(db.Model):
}
-# Attention: ce n'est pas un modèle mais une classe ordinaire:
-class RegroupementCoherentUE:
- """Le regroupement cohérent d'UE, dans la terminologie du BUT, est le couple d'UEs
- de la même année (BUT1,2,3) liées au *même niveau de compétence*.
-
- La moyenne (10/20) au RCUE déclenche la compensation des UE.
- """
-
- def __init__(
- self,
- etud: Identite,
- formsemestre_1: FormSemestre,
- dec_ue_1: "DecisionsProposeesUE",
- formsemestre_2: FormSemestre,
- dec_ue_2: "DecisionsProposeesUE",
- inscription_etat: str,
- ):
- ue_1 = dec_ue_1.ue
- ue_2 = dec_ue_2.ue
- # Ordonne les UE dans le sens croissant (S1,S2) ou (S3,S4)...
- if formsemestre_1.semestre_id > formsemestre_2.semestre_id:
- (ue_1, formsemestre_1), (ue_2, formsemestre_2) = (
- (ue_2, formsemestre_2),
- (ue_1, formsemestre_1),
- )
- assert formsemestre_1.semestre_id % 2 == 1
- assert formsemestre_2.semestre_id % 2 == 0
- assert abs(formsemestre_1.semestre_id - formsemestre_2.semestre_id) == 1
- assert ue_1.niveau_competence_id == ue_2.niveau_competence_id
- self.etud = etud
- self.formsemestre_1 = formsemestre_1
- "semestre impair"
- self.ue_1 = ue_1
- self.formsemestre_2 = formsemestre_2
- "semestre pair"
- self.ue_2 = ue_2
- # Stocke les moyennes d'UE
- if inscription_etat != scu.INSCRIT:
- self.moy_rcue = None
- self.moy_ue_1 = self.moy_ue_2 = "-"
- self.moy_ue_1_val = self.moy_ue_2_val = 0.0
- return
- self.moy_ue_1 = dec_ue_1.moy_ue_with_cap
- self.moy_ue_1_val = self.moy_ue_1 if self.moy_ue_1 is not None else 0.0
- self.moy_ue_2 = dec_ue_2.moy_ue_with_cap
- self.moy_ue_2_val = self.moy_ue_2 if self.moy_ue_2 is not None else 0.0
-
- # Calcul de la moyenne au RCUE (utilise les moy d'UE capitalisées)
- if (self.moy_ue_1 is not None) and (self.moy_ue_2 is not None):
- # Moyenne RCUE (les pondérations par défaut sont 1.)
- self.moy_rcue = (
- self.moy_ue_1 * ue_1.coef_rcue + self.moy_ue_2 * ue_2.coef_rcue
- ) / (ue_1.coef_rcue + ue_2.coef_rcue)
- else:
- self.moy_rcue = None
-
- def __repr__(self) -> str:
- return f"""<{self.__class__.__name__} {
- self.ue_1.acronyme}({self.moy_ue_1}) {
- self.ue_2.acronyme}({self.moy_ue_2})>"""
-
- def __str__(self) -> str:
- return f"""RCUE {
- self.ue_1.acronyme}({self.moy_ue_1}) + {
- self.ue_2.acronyme}({self.moy_ue_2})"""
-
- def query_validations(
- self,
- ) -> Query: # list[ApcValidationRCUE]
- """Les validations de jury enregistrées pour ce RCUE"""
- niveau = self.ue_2.niveau_competence
-
- return (
- ApcValidationRCUE.query.filter_by(
- etudid=self.etud.id,
- )
- .join(UniteEns, UniteEns.id == ApcValidationRCUE.ue2_id)
- .join(ApcNiveau, UniteEns.niveau_competence_id == ApcNiveau.id)
- .filter(ApcNiveau.id == niveau.id)
- )
-
- def other_ue(self, ue: UniteEns) -> UniteEns:
- """L'autre UE du regroupement. Si ue ne fait pas partie du regroupement, ValueError"""
- if ue.id == self.ue_1.id:
- return self.ue_2
- elif ue.id == self.ue_2.id:
- return self.ue_1
- raise ValueError(f"ue {ue} hors RCUE {self}")
-
- def est_enregistre(self) -> bool:
- """Vrai si ce RCUE, donc le niveau de compétences correspondant
- a une décision jury enregistrée
- """
- return self.query_validations().count() > 0
-
- def est_compensable(self):
- """Vrai si ce RCUE est validable (uniquement) par compensation
- c'est à dire que sa moyenne est > 10 avec une UE < 10.
- Note: si ADM, est_compensable est faux.
- """
- return (
- (self.moy_rcue is not None)
- and (self.moy_rcue > sco_codes.BUT_BARRE_RCUE)
- and (
- (self.moy_ue_1_val < sco_codes.NOTES_BARRE_GEN)
- or (self.moy_ue_2_val < sco_codes.NOTES_BARRE_GEN)
- )
- )
-
- def est_suffisant(self) -> bool:
- """Vrai si ce RCUE est > 8"""
- return (self.moy_rcue is not None) and (
- self.moy_rcue > sco_codes.BUT_RCUE_SUFFISANT
- )
-
- def est_validable(self) -> bool:
- """Vrai si ce RCUE satisfait les conditions pour être validé,
- c'est à dire que la moyenne des UE qui le constituent soit > 10
- """
- return (self.moy_rcue is not None) and (
- self.moy_rcue > sco_codes.BUT_BARRE_RCUE
- )
-
- def code_valide(self) -> Union[ApcValidationRCUE, None]:
- "Si ce RCUE est ADM, CMP ou ADJ, la validation. Sinon, None"
- validation = self.query_validations().first()
- if (validation is not None) and (
- validation.code in sco_codes.CODES_RCUE_VALIDES
- ):
- return validation
- return None
-
-
# unused
# def find_rcues(
# formsemestre: FormSemestre, ue: UniteEns, etud: Identite, inscription_etat: str
@@ -319,7 +183,7 @@ class ApcValidationAnnee(db.Model):
formsemestre_id = db.Column(
db.Integer, db.ForeignKey("notes_formsemestre.id"), nullable=True
)
- "le semestre IMPAIR (le 1er) de l'année"
+ "le semestre origine, normalement l'IMPAIR (le 1er) de l'année"
formation_id = db.Column(
db.Integer,
db.ForeignKey("notes_formations.id"),
diff --git a/app/models/events.py b/app/models/events.py
index d3e7709761..de93a24c0f 100644
--- a/app/models/events.py
+++ b/app/models/events.py
@@ -265,11 +265,8 @@ class ScolarNews(db.Model):
# Informations générales
H.append(
- f"""
- Pour être informé des évolutions de ScoDoc,
- vous pouvez vous
-
- abonner à la liste de diffusion.
+ f"""
"""
)
diff --git a/app/models/validations.py b/app/models/validations.py
index 10791758a0..9e2cf5e27d 100644
--- a/app/models/validations.py
+++ b/app/models/validations.py
@@ -68,7 +68,7 @@ class ScolarFormSemestreValidation(db.Model):
if self.ue_id:
# Note: si l'objet vient d'être créé, ue_id peut exister mais pas ue !
return f"""décision sur UE {self.ue.acronyme if self.ue else self.ue_id
- }: {self.code}"""
+ } ({self.ue_id}): {self.code}"""
return f"""décision sur semestre {self.formsemestre.titre_mois()} du {
self.event_date.strftime("%d/%m/%Y")}"""
diff --git a/app/scodoc/sco_formsemestre_edit.py b/app/scodoc/sco_formsemestre_edit.py
index 4a94f0bde8..67410b5c14 100644
--- a/app/scodoc/sco_formsemestre_edit.py
+++ b/app/scodoc/sco_formsemestre_edit.py
@@ -793,7 +793,13 @@ def do_formsemestre_createwithmodules(edit=False, formsemestre: FormSemestre = N
{tf[1]}
"""
elif tf[0] == -1:
- return "
annulation
"
+ return redirect(
+ url_for(
+ "notes.formsemestre_status",
+ scodoc_dept=g.scodoc_dept,
+ formsemestre_id=formsemestre.id,
+ )
+ )
else:
if tf[2]["gestion_compensation_lst"]:
tf[2]["gestion_compensation"] = True
diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py
index c163806eeb..17dd909f8f 100644
--- a/app/scodoc/sco_utils.py
+++ b/app/scodoc/sco_utils.py
@@ -520,7 +520,7 @@ SCO_DEFAULT_SQL_USERS_CNX = "dbname=SCOUSERS port=%s" % SCO_DEFAULT_SQL_PORT
# Valeurs utilisées pour affichage seulement, pas de requetes ni de mails envoyés:
SCO_WEBSITE = "https://scodoc.org"
SCO_USER_MANUAL = "https://scodoc.org/GuideUtilisateur"
-SCO_ANNONCES_WEBSITE = "https://listes.univ-paris13.fr/mailman/listinfo/scodoc-annonces"
+SCO_ANNONCES_WEBSITE = "https://scodoc.org/Contact"
SCO_DEVEL_LIST = "scodoc-devel@listes.univ-paris13.fr"
SCO_USERS_LIST = "notes@listes.univ-paris13.fr"
SCO_LISTS_URL = "https://scodoc.org/Contact"
diff --git a/app/static/js/scodoc.js b/app/static/js/scodoc.js
index 44b0352be3..b7de540872 100644
--- a/app/static/js/scodoc.js
+++ b/app/static/js/scodoc.js
@@ -1,291 +1,316 @@
// JS for all ScoDoc pages (using jQuery UI)
-
$(function () {
- // Autocomplete recherche etudiants par nom
- $(".in-expnom").autocomplete(
- {
- delay: 300, // wait 300ms before suggestions
- minLength: 2, // min nb of chars before suggest
- position: { collision: 'flip' }, // automatic menu position up/down
- source: SCO_URL + "/search_etud_by_name",
- select: function (event, ui) {
- $(".in-expnom").val(ui.item.value);
- $("#form-chercheetud").submit();
- }
- });
+ // Autocomplete recherche etudiants par nom
+ $(".in-expnom").autocomplete({
+ delay: 300, // wait 300ms before suggestions
+ minLength: 2, // min nb of chars before suggest
+ position: { collision: "flip" }, // automatic menu position up/down
+ source: SCO_URL + "/search_etud_by_name",
+ select: function (event, ui) {
+ $(".in-expnom").val(ui.item.value);
+ $("#form-chercheetud").submit();
+ },
+ });
- // Date picker
- $(".datepicker").datepicker({
- showOn: 'button',
- buttonImage: '/ScoDoc/static/icons/calendar_img.png',
- buttonImageOnly: true,
- dateFormat: 'dd/mm/yy',
- duration: 'fast',
- });
- $('.datepicker').datepicker('option', $.extend({ showMonthAfterYear: false },
- $.datepicker.regional['fr']));
+ // Date picker
+ $(".datepicker").datepicker({
+ showOn: "button",
+ buttonImage: "/ScoDoc/static/icons/calendar_img.png",
+ buttonImageOnly: true,
+ dateFormat: "dd/mm/yy",
+ duration: "fast",
+ });
+ $(".datepicker").datepicker(
+ "option",
+ $.extend({ showMonthAfterYear: false }, $.datepicker.regional["fr"])
+ );
- /* Barre menu */
- var sco_menu_position = { my: "left top", at: "left bottom" };
- $("#sco_menu").menu({
- position: sco_menu_position,
- blur: function () {
- $(this).menu("option", "position", sco_menu_position);
- },
- focus: function (e, ui) {
- if ($("#sco_menu").get(0) !== $(ui).get(0).item.parent().get(0)) {
- $(this).menu("option", "position", { my: "left top", at: "right top" });
- }
+ /* Barre menu */
+ var sco_menu_position = { my: "left top", at: "left bottom" };
+ $("#sco_menu")
+ .menu({
+ position: sco_menu_position,
+ blur: function () {
+ $(this).menu("option", "position", sco_menu_position);
+ },
+ focus: function (e, ui) {
+ if ($("#sco_menu").get(0) !== $(ui).get(0).item.parent().get(0)) {
+ $(this).menu("option", "position", {
+ my: "left top",
+ at: "right top",
+ });
}
- }).mouseleave(function (x, y) {
- $("#sco_menu").menu('collapseAll');
+ },
+ })
+ .mouseleave(function (x, y) {
+ $("#sco_menu").menu("collapseAll");
});
- $("#sco_menu > li > a > span").switchClass("ui-icon-carat-1-e", "ui-icon-carat-1-s");
+ $("#sco_menu > li > a > span").switchClass(
+ "ui-icon-carat-1-e",
+ "ui-icon-carat-1-s"
+ );
- /* Les menus isoles dropdown */
- $(".sco_dropdown_menu").menu({
- position: sco_menu_position
- }).mouseleave(function (x, y) {
- $(".sco_dropdown_menu").menu('collapseAll');
- }
- );
- $(".sco_dropdown_menu > li > a > span").switchClass("ui-icon-carat-1-e", "ui-icon-carat-1-s");
+ /* Les menus isoles dropdown */
+ $(".sco_dropdown_menu")
+ .menu({
+ position: sco_menu_position,
+ })
+ .mouseleave(function (x, y) {
+ $(".sco_dropdown_menu").menu("collapseAll");
+ });
+ $(".sco_dropdown_menu > li > a > span").switchClass(
+ "ui-icon-carat-1-e",
+ "ui-icon-carat-1-s"
+ );
- /* up-to-date status */
- var update_div = document.getElementById("update_warning");
- if (update_div) {
- fetch('install_info').then(
- response => response.text()
- ).then(text => {
- update_div.innerHTML = text;
- if (text) {
- update_div.style.display = "block";
- }
- });
- }
+ /* up-to-date status */
+ var update_div = document.getElementById("update_warning");
+ if (update_div) {
+ fetch("install_info")
+ .then((response) => response.text())
+ .then((text) => {
+ update_div.innerHTML = text;
+ if (text) {
+ update_div.style.display = "block";
+ }
+ });
+ }
});
function sco_capitalize(string) {
- return string[0].toUpperCase() + string.slice(1).toLowerCase();
+ return string[0].toUpperCase() + string.slice(1).toLowerCase();
}
// Affiche un message transitoire (duration milliseconds, 0 means infinity)
function sco_message(msg, className = "message_custom", duration = 0) {
- var div = document.createElement("div");
- div.className = className;
- div.innerHTML = msg;
- document.querySelector("body").appendChild(div);
- if (duration) {
- setTimeout(() => {
- div.remove();
- }, 3000);
- }
+ var div = document.createElement("div");
+ div.className = className;
+ div.innerHTML = msg;
+ document.querySelector("body").appendChild(div);
+ if (duration) {
+ setTimeout(() => {
+ div.remove();
+ }, 8000);
+ }
}
function sco_error_message(msg) {
- sco_message(msg, className = "message_error", duration = 0);
+ sco_message(msg, (className = "message_error"), (duration = 0));
}
-
function get_query_args() {
- var s = window.location.search; // eg "?x=1&y=2"
- var vars = {};
- s.replace(
- /[?&]+([^=&]+)=?([^&]*)?/gi, // regexp
- function (m, key, value) { // callback
- vars[key] = value !== undefined ? value : '';
- }
- );
- return vars;
+ var s = window.location.search; // eg "?x=1&y=2"
+ var vars = {};
+ s.replace(
+ /[?&]+([^=&]+)=?([^&]*)?/gi, // regexp
+ function (m, key, value) {
+ // callback
+ vars[key] = value !== undefined ? value : "";
+ }
+ );
+ return vars;
}
-
// Tables (gen_tables)
$(function () {
- if ($('table.gt_table').length > 0) {
- var table_options = {
- "paging": false,
- "searching": false,
- "info": false,
- /* "autoWidth" : false, */
- "fixedHeader": {
- "header": true,
- "footer": true
- },
- "orderCellsTop": true, // cellules ligne 1 pour tri
- "aaSorting": [], // Prevent initial sorting
- };
- $('table.gt_table').DataTable(table_options);
- table_options["searching"] = true;
- $('table.gt_table_searchable').DataTable(table_options);
- }
+ if ($("table.gt_table").length > 0) {
+ var table_options = {
+ paging: false,
+ searching: false,
+ info: false,
+ /* "autoWidth" : false, */
+ fixedHeader: {
+ header: true,
+ footer: true,
+ },
+ orderCellsTop: true, // cellules ligne 1 pour tri
+ aaSorting: [], // Prevent initial sorting
+ };
+ $("table.gt_table").DataTable(table_options);
+ table_options["searching"] = true;
+ $("table.gt_table_searchable").DataTable(table_options);
+ }
});
-
// Show tags (readonly)
function readOnlyTags(nodes) {
- // nodes are textareas, hide them and create a span showing tags
- for (var i = 0; i < nodes.length; i++) {
- var node = $(nodes[i]);
- node.hide();
- var tags = nodes[i].value.split(',');
- node.after('
' + tags.join('') + '');
- }
+ // nodes are textareas, hide them and create a span showing tags
+ for (var i = 0; i < nodes.length; i++) {
+ var node = $(nodes[i]);
+ node.hide();
+ var tags = nodes[i].value.split(",");
+ node.after(
+ '
' +
+ tags.join('') +
+ ""
+ );
+ }
}
/* Editeur pour champs
* Usage: créer un élément avec data-oid (object id)
- * La méthode d'URL save sera appelée en POST avec deux arguments: oid et value,
+ * La méthode d'URL save sera appelée en POST avec deux arguments: oid et value,
* value contenant la valeur du champs.
* Inspiré par les codes et conseils de Seb. L.
*/
class ScoFieldEditor {
- constructor(selector, save_url, read_only) {
- this.save_url = save_url;
- this.read_only = read_only;
- this.selector = selector;
- this.installListeners();
+ constructor(selector, save_url, read_only) {
+ this.save_url = save_url;
+ this.read_only = read_only;
+ this.selector = selector;
+ this.installListeners();
+ }
+ // Enregistre l'élément obj
+ save(obj) {
+ var value = obj.innerText.trim();
+ if (value.length == 0) {
+ value = "";
}
- // Enregistre l'élément obj
- save(obj) {
- var value = obj.innerText.trim();
- if (value.length == 0) {
- value = "";
- }
- if (value == obj.dataset.value) {
- return true; // Aucune modification, pas d'enregistrement mais on continue normalement
- }
- obj.classList.add("sco_wait");
- // DEBUG
- // console.log(`
- // data : ${value},
- // id: ${obj.dataset.oid}
- // `);
+ if (value == obj.dataset.value) {
+ return true; // Aucune modification, pas d'enregistrement mais on continue normalement
+ }
+ obj.classList.add("sco_wait");
+ // DEBUG
+ // console.log(`
+ // data : ${value},
+ // id: ${obj.dataset.oid}
+ // `);
- $.post(this.save_url,
- {
- oid: obj.dataset.oid,
- value: value,
- },
- function (result) {
- obj.classList.remove("sco_wait");
- obj.classList.add("sco_modified");
- }
- );
- return true;
+ $.post(
+ this.save_url,
+ {
+ oid: obj.dataset.oid,
+ value: value,
+ },
+ function (result) {
+ obj.classList.remove("sco_wait");
+ obj.classList.add("sco_modified");
+ }
+ );
+ return true;
+ }
+ /*****************************/
+ /* Gestion des évènements */
+ /*****************************/
+ installListeners() {
+ if (this.read_only) {
+ return;
}
- /*****************************/
- /* Gestion des évènements */
- /*****************************/
- installListeners() {
- if (this.read_only) {
- return;
+ document.body.addEventListener("keydown", this.key);
+ let editor = this;
+ this.handleSelectCell = (event) => {
+ editor.selectCell(event);
+ };
+ this.handleModifCell = (event) => {
+ editor.modifCell(event);
+ };
+ this.handleBlur = (event) => {
+ editor.blurCell(event);
+ };
+ this.handleKeyCell = (event) => {
+ editor.keyCell(event);
+ };
+ document.querySelectorAll(this.selector).forEach((cellule) => {
+ cellule.addEventListener("click", this.handleSelectCell);
+ cellule.addEventListener("dblclick", this.handleModifCell);
+ cellule.addEventListener("blur", this.handleBlur);
+ });
+ }
+ /*********************************/
+ /* Interaction avec les cellules */
+ /*********************************/
+ blurCell(event) {
+ let currentModif = document.querySelector(".sco_modifying");
+ if (currentModif) {
+ if (!this.save(currentModif)) {
+ return;
+ }
+ }
+ }
+ selectCell(event) {
+ let obj = event.currentTarget;
+ if (obj) {
+ if (obj.classList.contains("sco_modifying")) {
+ return; // Cellule en cours de modification, ne pas sélectionner.
+ }
+ let currentModif = document.querySelector(".sco_modifying");
+ if (currentModif) {
+ if (!this.save(currentModif)) {
+ return;
}
- document.body.addEventListener("keydown", this.key);
- let editor = this;
- this.handleSelectCell = (event) => { editor.selectCell(event) };
- this.handleModifCell = (event) => { editor.modifCell(event) };
- this.handleBlur = (event) => { editor.blurCell(event) };
- this.handleKeyCell = (event) => { editor.keyCell(event) };
- document.querySelectorAll(this.selector).forEach(cellule => {
- cellule.addEventListener("click", this.handleSelectCell);
- cellule.addEventListener("dblclick", this.handleModifCell);
- cellule.addEventListener("blur", this.handleBlur);
- });
- }
- /*********************************/
- /* Interaction avec les cellules */
- /*********************************/
- blurCell(event) {
- let currentModif = document.querySelector(".sco_modifying");
- if (currentModif) {
- if (!this.save(currentModif)) {
- return;
- }
- }
- }
- selectCell(event) {
- let obj = event.currentTarget;
- if (obj) {
- if (obj.classList.contains("sco_modifying")) {
- return; // Cellule en cours de modification, ne pas sélectionner.
- }
- let currentModif = document.querySelector(".sco_modifying");
- if (currentModif) {
- if (!this.save(currentModif)) {
- return;
- }
- }
+ }
- this.unselectCell();
- obj.classList.add("sco_selected");
- }
- }
- unselectCell() {
- document.querySelectorAll(".sco_selected, .sco_modifying").forEach(cellule => {
- cellule.classList.remove("sco_selected", "sco_modifying");
- cellule.removeAttribute("contentEditable");
- cellule.removeEventListener("keydown", this.handleKeyCell);
- });
- }
- modifCell(event) {
- let obj = event.currentTarget;
- if (obj) {
- obj.classList.add("sco_modifying");
- obj.contentEditable = true;
- obj.addEventListener("keydown", this.handleKeyCell);
- obj.focus();
- }
- }
- key(event) {
- switch (event.key) {
- case "Enter":
- this.modifCell(document.querySelector(".sco_selected"));
- event.preventDefault();
- break;
- }
- }
- keyCell(event) {
- let obj = event.currentTarget;
- if (obj) {
- if (event.key == "Enter") {
- event.preventDefault();
- event.stopPropagation();
- if (!this.save(obj)) {
- return
- }
- obj.classList.remove("sco_modifying");
- // ArrowMove(0, 1);
- // modifCell(document.querySelector(".sco_selected"));
- this.unselectCell();
- }
+ this.unselectCell();
+ obj.classList.add("sco_selected");
+ }
+ }
+ unselectCell() {
+ document
+ .querySelectorAll(".sco_selected, .sco_modifying")
+ .forEach((cellule) => {
+ cellule.classList.remove("sco_selected", "sco_modifying");
+ cellule.removeAttribute("contentEditable");
+ cellule.removeEventListener("keydown", this.handleKeyCell);
+ });
+ }
+ modifCell(event) {
+ let obj = event.currentTarget;
+ if (obj) {
+ obj.classList.add("sco_modifying");
+ obj.contentEditable = true;
+ obj.addEventListener("keydown", this.handleKeyCell);
+ obj.focus();
+ }
+ }
+ key(event) {
+ switch (event.key) {
+ case "Enter":
+ this.modifCell(document.querySelector(".sco_selected"));
+ event.preventDefault();
+ break;
+ }
+ }
+ keyCell(event) {
+ let obj = event.currentTarget;
+ if (obj) {
+ if (event.key == "Enter") {
+ event.preventDefault();
+ event.stopPropagation();
+ if (!this.save(obj)) {
+ return;
}
+ obj.classList.remove("sco_modifying");
+ // ArrowMove(0, 1);
+ // modifCell(document.querySelector(".sco_selected"));
+ this.unselectCell();
+ }
}
+ }
}
function getCurrentScriptPath() {
- // Get all the script elements on the page
- var scripts = document.getElementsByTagName('script');
+ // Get all the script elements on the page
+ var scripts = document.getElementsByTagName("script");
- // Find the last script element (which is the currently executing script)
- var currentScript = scripts[scripts.length - 1];
+ // Find the last script element (which is the currently executing script)
+ var currentScript = scripts[scripts.length - 1];
- // Retrieve the src attribute of the script element
- var scriptPath = currentScript.src;
+ // Retrieve the src attribute of the script element
+ var scriptPath = currentScript.src;
- return scriptPath;
+ return scriptPath;
}
function removeLastTwoComponents(path) {
- // Split the path into individual components
- var components = path.split('/');
+ // Split the path into individual components
+ var components = path.split("/");
- // Remove the last two components (filename and enclosing directory)
- components.splice(-2);
+ // Remove the last two components (filename and enclosing directory)
+ components.splice(-2);
- // Join the remaining components back into a path
- var newPath = components.join('/');
+ // Join the remaining components back into a path
+ var newPath = components.join("/");
- return newPath;
+ return newPath;
}
diff --git a/app/tables/jury_recap.py b/app/tables/jury_recap.py
index 3e6f5d24da..aca2491399 100644
--- a/app/tables/jury_recap.py
+++ b/app/tables/jury_recap.py
@@ -74,9 +74,8 @@ class TableJury(TableRecap):
self.freq_codes_annuels[deca.code_valide] += 1
row.add_nb_rcues_cell()
# --- Les RCUEs
- for rcue in deca.rcues_annee:
- dec_rcue = deca.dec_rcue_by_ue.get(rcue.ue_1.id)
- if dec_rcue is not None: # None si l'UE n'est pas associée à un niveau
+ for dec_rcue in deca.get_decisions_rcues_annee():
+ if dec_rcue.rcue.complete:
row.add_rcue_cols(dec_rcue)
self.freq_codes_annuels["total"] = len(self.rows)
@@ -205,7 +204,7 @@ class RowJury(RowRecap):
else:
classes.append("moy_ue_valid")
- if len(deca.rcues_annee) > 0:
+ if len(deca.get_decisions_rcues_annee()) > 0:
# permet un tri par nb de niveaux validables + moyenne gen indicative S_pair
if deca.res_pair and deca.etud.id in deca.res_pair.etud_moy_gen:
moy = deca.res_pair.etud_moy_gen[deca.etud.id]
@@ -260,9 +259,11 @@ class RowJury(RowRecap):
def add_rcue_cols(self, dec_rcue: DecisionsProposeesRCUE):
"2 cells: moyenne du RCUE, code enregistré"
- self.table.group_titles["rcue"] = "RCUEs en cours"
rcue = dec_rcue.rcue
- col_id = f"moy_rcue_{rcue.ue_1.niveau_competence_id}" # le niveau_id
+ if not rcue.complete:
+ return
+ col_id = f"moy_rcue_{rcue.niveau.id}" # le niveau_id
+ self.table.group_titles["rcue"] = "RCUEs en cours"
note_class = ""
val = rcue.moy_rcue
if isinstance(val, float):
diff --git a/app/templates/but/documentation_codes_jury.j2 b/app/templates/but/documentation_codes_jury.j2
index 3ea9c80dec..25d051e57b 100644
--- a/app/templates/but/documentation_codes_jury.j2
+++ b/app/templates/but/documentation_codes_jury.j2
@@ -130,6 +130,12 @@
CODJ |
Acquis par décision du jury |
+
+ ADSUP |
+ {{codes["ADSUP"]}} |
+ |
+ Acquis parce que le niveau de compétence supérieur est acquis |
+
AJ |
{{codes["AJ"]}} |
@@ -200,6 +206,12 @@
|
Acquis par décision de jury sur le RCUE (ECTS acquis) |
+
+ ADSUP |
+ {{codes["ADSUP"]}} |
+ |
+ Acquis parce que le niveau de compétence supérieur est acquis |
+
AJ |
{{codes["AJ"]}} |
diff --git a/app/templates/pn/ue_infos.j2 b/app/templates/pn/ue_infos.j2
index 071b1b8731..61ead8e011 100644
--- a/app/templates/pn/ue_infos.j2
+++ b/app/templates/pn/ue_infos.j2
@@ -13,6 +13,7 @@
- Semestre: {{ue.semestre_idx}}
- Code: {{ue.ue_code}}
+ - ECTS: {{ue.ects or 0}}
- Type: {{ue.type}}
- Externe: {{ "oui" if ue.is_external else "non" }}
- Code Apogée: {{ue.code_apogee or "aucun"}}
diff --git a/app/views/notes.py b/app/views/notes.py
index 3b1772982d..6483c51021 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -2430,7 +2430,7 @@ def formsemestre_validation_but(
)
deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
- if len(deca.rcues_annee) == 0:
+ if len(deca.get_decisions_rcues_annee()) == 0:
return jury_but_view.jury_but_semestriel(
formsemestre, etud, read_only, navigation_div=navigation_div
)
@@ -2459,22 +2459,25 @@ def formsemestre_validation_but(
warning = ""
if len(deca.niveaux_competences) != len(deca.decisions_rcue_by_niveau):
- if deca.a_cheval:
- warning += """Attention: regroupements RCUE
- entre années (redoublement).
"""
- else:
- warning += f"""Attention: {len(deca.niveaux_competences)}
+ warning += f"""
Attention: {len(deca.niveaux_competences)}
niveaux mais {len(deca.decisions_rcue_by_niveau)} regroupements RCUE.
"""
if (deca.parcour is None) and len(formsemestre.parcours) > 0:
warning += (
"""
L'étudiant n'est pas inscrit à un parcours.
"""
)
- if deca.formsemestre_impair and deca.inscription_etat_impair != scu.INSCRIT:
- etat_ins = scu.ETATS_INSCRIPTION.get(deca.inscription_etat_impair, "inconnu?")
- warning += f"""
{etat_ins} en S{deca.formsemestre_impair.semestre_id}
"""
- if deca.formsemestre_pair and deca.inscription_etat_pair != scu.INSCRIT:
- etat_ins = scu.ETATS_INSCRIPTION.get(deca.inscription_etat_pair, "inconnu?")
- warning += f"""
{etat_ins} en S{deca.formsemestre_pair.semestre_id}
"""
+
+ if deca.formsemestre_impair:
+ inscription = deca.formsemestre_impair.etuds_inscriptions.get(etud.id)
+ if (not inscription) or inscription.etat != scu.INSCRIT:
+ etat_ins = scu.ETATS_INSCRIPTION.get(inscription.etat, "inconnu?")
+ warning += f"""
{etat_ins} en S{deca.formsemestre_impair.semestre_id}
"""
+
+ if deca.formsemestre_pair:
+ inscription = deca.formsemestre_pair.etuds_inscriptions.get(etud.id)
+ if (not inscription) or inscription.etat != scu.INSCRIT:
+ etat_ins = scu.ETATS_INSCRIPTION.get(inscription.etat, "inconnu?")
+ warning += f"""
{etat_ins} en S{deca.formsemestre_pair.semestre_id}
"""
+
if deca.has_notes_en_attente():
warning += f"""
{etud.nomprenom} a des notes en ATTente.
Vous devriez régler cela avant de statuer en jury !
"""
@@ -2531,7 +2534,7 @@ def formsemestre_validation_but(
else:
erase_span = f"""
effacer décisions de ce jury
@@ -2564,15 +2567,7 @@ def formsemestre_validation_but(
)
H.append(navigation_div)
H.append("")
- if deca.a_cheval:
- H.append(
- f"""
- {scu.EMO_WARNING} Rappel: pour les redoublants, seules les UE capitalisées (note > 10)
- lors d'une année précédente peuvent être prise en compte pour former
- un RCUE (associé à un niveau de compétence du BUT).
-
- """
- )
+
# Affichage cursus BUT
but_cursus = cursus_but.EtudCursusBUT(etud, deca.formsemestre.formation)
H += [
@@ -2595,7 +2590,14 @@ def formsemestre_validation_but(
codes=ScoDocSiteConfig.get_codes_apo_dict(),
)
)
-
+ H.append(
+ f"""
+ {scu.EMO_WARNING} Rappel: pour les redoublants, seules les UE capitalisées (note > 10)
+ lors d'une année précédente peuvent être prise en compte pour former
+ un RCUE (associé à un niveau de compétence du BUT).
+
+ """
+ )
return "\n".join(H) + html_sco_header.sco_footer()
diff --git a/sco_version.py b/sco_version.py
index 282f517e7f..aa68bec3df 100644
--- a/sco_version.py
+++ b/sco_version.py
@@ -1,7 +1,7 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
-SCOVERSION = "9.4.93"
+SCOVERSION = "9.4.94"
SCONAME = "ScoDoc"