Compare commits

..

No commits in common. "989930e4ce94c9d93771dcc737197d2df43d0383" and "a297126c1ccf62ad032bb1004d001f625b5a3a57" have entirely different histories.

12 changed files with 82 additions and 160 deletions

View File

@ -473,7 +473,7 @@ def etudiant_bulletin_semestre( # XXX TODO Ajouter la possibilité de retourner
return response
return sco_bulletins.get_formsemestre_bulletin_etud_json(
formsemestre, etud, version=version
formsemestre, etud, version
)

View File

@ -650,7 +650,7 @@ class ResultatsSemestre(ResultatsCache):
elif nb_ues_validables < len(ues_sans_bonus):
row["_ues_validables_class"] += " moy_inf"
row["_ues_validables_order"] = nb_ues_validables # pour tri
if mode_jury and self.validations:
if mode_jury:
dec_sem = self.validations.decisions_jury.get(etudid)
jury_code_sem = dec_sem["code"] if dec_sem else ""
idx = add_cell(

View File

@ -451,7 +451,6 @@ class ApcAppCritique(db.Model, XMLModel):
if competence is not None:
query = query.filter(ApcNiveau.competence == competence)
return query
<<<<<<< HEAD
def __init__(self, id, niveau_id, code, libelle, modules):
self.id = id
@ -459,8 +458,6 @@ class ApcAppCritique(db.Model, XMLModel):
self.code = code
self.libelle = libelle
self.modules = modules
=======
>>>>>>> 7c340c798ad59c41653efc83bfd079f11fce1938
def to_dict(self) -> dict:
return {"libelle": self.libelle}
@ -547,14 +544,11 @@ class ApcAnneeParcours(db.Model, XMLModel):
)
ordre = db.Column(db.Integer)
"numéro de l'année: 1, 2, 3"
<<<<<<< HEAD
def __init__(self, id, parcours_id, ordre):
self.id = id
self.parcours_id = parcours_id
self.ordre = ordre
=======
>>>>>>> 7c340c798ad59c41653efc83bfd079f11fce1938
def __repr__(self):
return f"<{self.__class__.__name__} ordre={self.ordre!r} parcours={self.parcours.code!r}>"

View File

@ -43,7 +43,6 @@ class ApcValidationRCUE(db.Model):
formsemestre_id = db.Column(
db.Integer, db.ForeignKey("notes_formsemestre.id"), index=True, nullable=True
)
"formsemestre pair du RCUE"
# Les deux UE associées à ce niveau:
ue1_id = db.Column(db.Integer, db.ForeignKey("notes_ue.id"), nullable=False)
ue2_id = db.Column(db.Integer, db.ForeignKey("notes_ue.id"), nullable=False)

View File

@ -58,6 +58,7 @@ from app.scodoc import sco_formations
from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups
from app.scodoc import sco_permissions_check
from app.scodoc import sco_photos
from app.scodoc import sco_preferences
from app.scodoc import sco_pvjury
from app.scodoc import sco_users
@ -65,6 +66,15 @@ import app.scodoc.sco_utils as scu
from app.scodoc.sco_utils import ModuleType, fmt_note
import app.scodoc.notesdb as ndb
# ----- CLASSES DE BULLETINS DE NOTES
from app.scodoc import sco_bulletins_standard
from app.scodoc import sco_bulletins_legacy
# import sco_bulletins_example # format exemple (à désactiver en production)
# ... ajouter ici vos modules ...
from app.scodoc import sco_bulletins_ucac # format expérimental UCAC Cameroun
def get_formsemestre_bulletin_etud_json(
formsemestre: FormSemestre,

View File

@ -92,6 +92,7 @@ def formsemestre_bulletinetud_published_dict(
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
d = {"type": "classic", "version": "0"}
if (not sem["bul_hide_xml"]) or force_publishing:
published = True
else:
@ -133,7 +134,6 @@ def formsemestre_bulletinetud_published_dict(
)
d["etudiant"]["sexe"] = d["etudiant"]["civilite"] # backward compat for our clients
# Disponible pour publication ?
d["publie"] = published
if not published:
return d # stop !
@ -364,35 +364,8 @@ def formsemestre_bulletinetud_published_dict(
return d
def dict_decision_jury(etudid, formsemestre_id, with_decisions=False) -> dict:
"""dict avec decision pour bulletins json
- decision : décision semestre
- decision_ue : list des décisions UE
- situation
with_decision donne les décision même si bul_show_decision est faux.
Exemple:
{
'autorisation_inscription': [{'semestre_id': 4}],
'decision': {'code': 'ADM',
'compense_formsemestre_id': None,
'date': '2022-01-21',
'etat': 'I'},
'decision_ue': [
{
'acronyme': 'UE31',
'code': 'ADM',
'ects': 16.0,
'numero': 23,
'titre': 'Approfondissement métiers',
'ue_id': 1787
},
...
],
'situation': 'Inscrit le 25/06/2021. Décision jury: Validé. UE acquises: '
'UE31, UE32. Diplôme obtenu.'}
"""
def dict_decision_jury(etudid, formsemestre_id, with_decisions=False):
"dict avec decision pour bulletins json"
from app.scodoc import sco_bulletins
d = {}

View File

@ -35,17 +35,13 @@ from app.models.etudiants import Identite
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
from app import db, log
from app import log
from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre
from app.models.notes import etud_has_notes_attente
from app.models.validations import (
ScolarAutorisationInscription,
ScolarFormSemestreValidation,
)
from app.models.but_validations import ApcValidationRCUE, ApcValidationAnnee
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc.scolog import logdb
from app.scodoc.sco_codes_parcours import *
@ -993,32 +989,28 @@ def do_formsemestre_validation_auto(formsemestre_id):
def formsemestre_validation_suppress_etud(formsemestre_id, etudid):
"""Suppression des décisions de jury pour un étudiant/formsemestre.
Efface toutes les décisions enregistrées concernant ce formsemestre et cet étudiant:
code semestre, UEs, autorisations d'inscription
"""
log(f"formsemestre_validation_suppress_etud( {formsemestre_id}, {etudid})")
# Validations jury classiques (semestres, UEs, autorisations)
for v in ScolarFormSemestreValidation.query.filter_by(
etudid=etudid, formsemestre_id=formsemestre_id
):
db.session.delete(v)
for v in ScolarAutorisationInscription.query.filter_by(
etudid=etudid, origin_formsemestre_id=formsemestre_id
):
db.session.delete(v)
# Validations jury spécifiques BUT
for v in ApcValidationRCUE.query.filter_by(
etudid=etudid, formsemestre_id=formsemestre_id
):
db.session.delete(v)
for v in ApcValidationAnnee.query.filter_by(
etudid=etudid, formsemestre_id=formsemestre_id
):
db.session.delete(v)
db.session.commit()
"""Suppression des decisions de jury pour un etudiant."""
log("formsemestre_validation_suppress_etud( %s, %s)" % (formsemestre_id, etudid))
cnx = ndb.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
args = {"formsemestre_id": formsemestre_id, "etudid": etudid}
try:
# -- Validation du semestre et des UEs
cursor.execute(
"""delete from scolar_formsemestre_validation
where etudid = %(etudid)s and formsemestre_id=%(formsemestre_id)s""",
args,
)
# -- Autorisations d'inscription
cursor.execute(
"""delete from scolar_autorisation_inscription
where etudid = %(etudid)s and origin_formsemestre_id=%(formsemestre_id)s""",
args,
)
cnx.commit()
except:
cnx.rollback()
raise
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
_invalidate_etud_formation_caches(

View File

@ -224,26 +224,9 @@ class releveBUT extends HTMLElement {
<div class=abs>Non justifiées</div>
<div>${data.semestre.absences?.injustifie ?? "-"}</div>
<div class=abs>Total</div><div>${data.semestre.absences?.total ?? "-"}</div>
</div>`;
if(data.semestre.decision_rcue?.length){
output += `
<div>
<div class=enteteSemestre>RCUE</div><div></div>
${(()=>{
let output = "";
data.semestre.decision_rcue.forEach(competence=>{
output += `<div class=rang>${competence.niveau.competence.titre}</div><div>${competence.code}</div>`;
})
return output;
})()}
</div>
</div>`
}
output += `
<a class=photo href="${data.etudiant.fiche_url}">
<img src="${data.etudiant.photo_url || "default_Student.svg"}" alt="photo de l'étudiant" title="fiche de l'étudiant" height="120" border="0">
</a>`;
<a class=photo href="${data.etudiant.fiche_url}"><img src="${data.etudiant.photo_url || "default_Student.svg"}" alt="photo de l'étudiant" title="fiche de l'étudiant" height="120" border="0"></a>
`;
/*${data.semestre.groupes.map(groupe => {
return `
<div>
@ -257,11 +240,9 @@ class releveBUT extends HTMLElement {
}).join("")
}*/
this.shadow.querySelector(".infoSemestre").innerHTML = output;
/*if(data.semestre.decision_annee?.code){
if(data.semestre.decision_annee?.code){
this.shadow.querySelector(".decision_annee").innerHTML = "Décision année : " + data.semestre.decision_annee.code + " - " + correspondanceCodes[data.semestre.decision_annee.code];
}*/
}
this.shadow.querySelector(".decision").innerHTML = data.semestre.situation || "";
/*if (data.semestre.decision?.code) {

View File

@ -258,7 +258,7 @@
<li><a href="https://www.enseignementsup-recherche.gouv.fr/fr/bo/21/Special4/ESRS2114777A.htm">Bulletin
officiel spécial n°4 du 17 juin 2021</a></li>
<li><a
href="https://cache.media.enseignementsup-recherche.gouv.fr//file/SPE4-MESRI-17-6-2021/19/4/SP4_ESR_17_6_2021_1413194.pdf">Version
href="https://cache.media.enseignementsup-recherche.gouv.fr//file/SPE4-MESRI-17-6-2021/19/4/SP4_ESR_17_6_2021_1413194.pdf">version
pdf complète</a></li>
</ul>

View File

@ -57,7 +57,7 @@ from app.models.ues import UniteEns
from app import api
from app import db
from app import models
from app.models import ScolarNews, but_validations
from app.models import ScolarNews
from app.auth.models import User
from app.but import apc_edit_ue, jury_but_recap
from app.decorators import (
@ -71,7 +71,7 @@ from app.views import notes_bp as bp
# ---------------
from app.scodoc import sco_bulletins_json, sco_utils as scu
from app.scodoc import sco_utils as scu
from app.scodoc import notesdb as ndb
from app import log, send_scodoc_alarm
@ -2143,16 +2143,6 @@ def formsemestre_validation_etud_form(
):
"Formulaire choix jury pour un étudiant"
readonly = not sco_permissions_check.can_validate_sem(formsemestre_id)
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
if formsemestre.formation.is_apc():
return redirect(
url_for(
"notes.formsemestre_validation_but",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
etudid=etudid,
)
)
return sco_formsemestre_validation.formsemestre_validation_etud_form(
formsemestre_id,
etudid=etudid,
@ -2525,68 +2515,51 @@ def do_formsemestre_validation_auto(formsemestre_id):
def formsemestre_validation_suppress_etud(
formsemestre_id, etudid, dialog_confirmed=False
):
"""Suppression des décisions de jury pour un étudiant."""
"""Suppression des decisions de jury pour un etudiant."""
if not sco_permissions_check.can_validate_sem(formsemestre_id):
return scu.confirm_dialog(
message="<p>Opération non autorisée pour %s</h2>" % current_user,
dest_url=scu.ScoURL(),
)
etud = Identite.query.get_or_404(etudid)
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
if formsemestre.formation.is_apc():
next_url = url_for(
"scolar.ficheEtud",
scodoc_dept=g.scodoc_dept,
etudid=etudid,
)
else:
next_url = url_for(
"notes.formsemestre_validation_etud_form",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
etudid=etudid,
)
if not dialog_confirmed:
d = sco_bulletins_json.dict_decision_jury(
etudid, formsemestre_id, with_decisions=True
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
sem = formsemestre.to_dict()
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
decision_jury = nt.get_etud_decision_sem(etudid)
if decision_jury:
existing = (
"<p>Décision existante: %(code)s du %(event_date)s</p>" % decision_jury
)
d.update(but_validations.dict_decision_jury(etud, formsemestre))
descr_ues = [f"{u['acronyme']}: {u['code']}" for u in d.get("decision_ue", [])]
dec_annee = d.get("decision_annee")
if dec_annee:
descr_annee = dec_annee.get("code", "-")
else:
descr_annee = "-"
existing = f"""
<ul>
<li>Semestre : {d.get("decision", {"code":"-"})['code'] or "-"}</li>
<li>Année BUT: {descr_annee}</li>
<li>UEs : {", ".join(descr_ues)}</li>
<li>RCUEs: {len(d.get("decision_rcue", []))} décisions</li>
</ul>
"""
existing = ""
return scu.confirm_dialog(
f"""<h2>Confirmer la suppression des décisions du semestre
{formsemestre.titre_mois()} pour {etud.nomprenom}
</h2>
<p>Cette opération est irréversible.</p>
<div>
{existing}
</div>
""",
"""<h2>Confirmer la suppression des décisions du semestre %s (%s - %s) pour %s ?</h2>%s
<p>Cette opération est irréversible.
</p>
"""
% (
sem["titre_num"],
sem["date_debut"],
sem["date_fin"],
etud["nomprenom"],
existing,
),
OK="Supprimer",
dest_url="",
cancel_url=next_url,
cancel_url="formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s"
% (formsemestre_id, etudid),
parameters={"etudid": etudid, "formsemestre_id": formsemestre_id},
)
sco_formsemestre_validation.formsemestre_validation_suppress_etud(
formsemestre_id, etudid
)
flash("Décisions supprimées")
return flask.redirect(next_url)
return flask.redirect(
scu.ScoURL()
+ "/Notes/formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&head_message=Décision%%20supprimée"
% (formsemestre_id, etudid)
)
# ------------- PV de JURY et archives

View File

@ -1,7 +1,7 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
SCOVERSION = "9.3.16"
SCOVERSION = "9.3.15"
SCONAME = "ScoDoc"

View File

@ -33,7 +33,7 @@ except NameError:
load_dotenv(os.path.join(BASEDIR, ".env"))
CHK_CERT = bool(int(os.environ.get("CHECK_CERTIFICATE", False)))
SCODOC_URL = os.environ.get("SCODOC_URL") or "http://localhost:5000"
SCODOC_URL = os.environ["SCODOC_URL"] or "http://localhost:5000"
API_URL = SCODOC_URL + "/ScoDoc/api"
SCODOC_USER = os.environ["SCODOC_USER"]
SCODOC_PASSWORD = os.environ["SCODOC_PASSWORD"]
@ -85,13 +85,13 @@ if r.status_code != 200:
print(f"{len(r.json())} étudiants courants")
# Bulletin d'un BUT
formsemestre_id = 1063 # A adapter
etudid = 16450
formsemestre_id = 1052 # A adapter
etudid = 16400
bul = GET(f"/etudiant/etudid/{etudid}/formsemestre/{formsemestre_id}/bulletin")
# d'un DUT
formsemestre_id = 1062 # A adapter
etudid = 16309
formsemestre_id = 1028 # A adapter
etudid = 14721
bul_dut = GET(f"/etudiant/etudid/{etudid}/formsemestre/{formsemestre_id}/bulletin")