Update opolka/ScoDoc from ScoDoc/ScoDoc #2

Merged
opolka merged 1272 commits from ScoDoc/ScoDoc:master into master 2024-05-27 09:11:04 +02:00
4 changed files with 148 additions and 33 deletions
Showing only changes of commit cf74708f83 - Show all commits

View File

@ -30,16 +30,17 @@
from flask import url_for, g from flask import url_for, g
from app import db from app import db
from app.models import Evaluation, FormSemestre, Identite from app.models import Evaluation, FormSemestre, Identite, Assiduite
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import sco_evaluations from app.scodoc import sco_evaluations
from app.scodoc import sco_evaluation_db from app.scodoc import sco_evaluation_db
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc import sco_groups from app.scodoc import sco_groups
from flask_sqlalchemy.query import Query
from sqlalchemy import or_, and_
# XXX TODO-ASSIDUITE https://scodoc.org/git/ScoDoc/ScoDoc/issues/685
def evaluation_check_absences(evaluation: Evaluation): def evaluation_check_absences(evaluation: Evaluation):
"""Vérifie les absences au moment de cette évaluation. """Vérifie les absences au moment de cette évaluation.
Cas incohérents que l'on peut rencontrer pour chaque étudiant: Cas incohérents que l'on peut rencontrer pour chaque étudiant:
@ -50,28 +51,32 @@ def evaluation_check_absences(evaluation: Evaluation):
EXC et pas justifie EXC et pas justifie
Ramene 5 listes d'etudid Ramene 5 listes d'etudid
""" """
raise ScoValueError("Fonction non disponible, patience !") # XXX TODO-ASSIDUITE
if not evaluation.date_debut: if not evaluation.date_debut:
return [], [], [], [], [] # evaluation sans date return [], [], [], [], [] # evaluation sans date
am, pm = evaluation.is_matin(), evaluation.is_apresmidi() etudids = [
etudid
for etudid, _ in sco_groups.do_evaluation_listeetuds_groups(
evaluation.id, getallstudents=True
)
]
# Liste les absences à ce moment: deb, fin = scu.localize_datetime(evaluation.date_debut), scu.localize_datetime(
absences = sco_abs.list_abs_jour(evaluation.date_debut, am=am, pm=pm) evaluation.date_fin
abs_etudids = set([x["etudid"] for x in absences]) # ensemble des etudiants absents
abs_non_just = sco_abs.list_abs_non_just_jour(
evaluation.date_debut.date(), am=am, pm=pm
) )
abs_nj_etudids = set(
[x["etudid"] for x in abs_non_just] assiduites: Query = Assiduite.query.filter(
) # ensemble des etudiants absents non justifies Assiduite.etudid.in_(etudids),
justifs = sco_abs.list_abs_jour( Assiduite.etat == scu.EtatAssiduite.ABSENT,
evaluation.date_debut.date(), am=am, pm=pm, is_abs=None, is_just=True or_(
and_(Assiduite.date_debut >= deb, Assiduite.date_debut <= fin),
and_(Assiduite.date_fin >= deb, Assiduite.date_fin <= fin),
),
) )
just_etudids = set(
[x["etudid"] for x in justifs] abs_etudids = set(assi.etudid for assi in assiduites)
) # ensemble des etudiants avec justif abs_nj_etudids = set(assi.etudid for assi in assiduites if assi.est_just is False)
just_etudids = set(assi.etudid for assi in assiduites if assi.est_just is True)
# Les notes: # Les notes:
notes_db = sco_evaluation_db.do_evaluation_get_all_notes(evaluation.id) notes_db = sco_evaluation_db.do_evaluation_get_all_notes(evaluation.id)
@ -80,9 +85,7 @@ def evaluation_check_absences(evaluation: Evaluation):
ExcNonSignalee = [] # note EXC mais pas noté absent ExcNonSignalee = [] # note EXC mais pas noté absent
ExcNonJust = [] # note EXC mais absent non justifie ExcNonJust = [] # note EXC mais absent non justifie
AbsButExc = [] # note ABS mais justifié AbsButExc = [] # note ABS mais justifié
for etudid, _ in sco_groups.do_evaluation_listeetuds_groups( for etudid in etudids:
evaluation.id, getallstudents=True
):
if etudid in notes_db: if etudid in notes_db:
val = notes_db[etudid]["value"] val = notes_db[etudid]["value"]
if ( if (
@ -170,14 +173,10 @@ def evaluation_check_absences_html(
) )
if linkabs: if linkabs:
url = url_for( url = url_for(
"absences.doSignaleAbsence", # XXX TODO-ASSIDUITE "assiduites.signal_evaluation_abs",
scodoc_dept=g.scodoc_dept,
etudid=etudid, etudid=etudid,
# par defaut signale le jour du début de l'éval evaluation_id=evaluation.id,
datedebut=evaluation.date_debut.strftime("%d/%m/%Y"), scodoc_dept=g.scodoc_dept,
datefin=evaluation.date_debut.strftime("%d/%m/%Y"),
demijournee=demijournee,
moduleimpl_id=evaluation.moduleimpl_id,
) )
H.append( H.append(
f"""<a class="stdlink" href="{url}">signaler cette absence</a>""" f"""<a class="stdlink" href="{url}">signaler cette absence</a>"""

View File

@ -32,6 +32,18 @@
</div> </div>
</div> </div>
<hr> <hr>
{% if saisie_eval %}
<div id="saisie_eval">
<br>
<h3>
La saisie de l'assiduité a été préconfigurée en fonction de l'évaluation. <br>
Une fois la saisie finie, cliquez sur le lien si dessous pour revenir sur la gestion de l'évaluation
</h3>
<a href="{{redirect_url}}">retourner sur la page de l'évaluation</a>
</div>
{% endif %}
{{diff | safe}} {{diff | safe}}
<div class="legende"> <div class="legende">
@ -118,7 +130,20 @@
window.forceModule = "{{ forcer_module }}" window.forceModule = "{{ forcer_module }}"
window.forceModule = window.forceModule == "True" ? true : false window.forceModule = window.forceModule == "True" ? true : false
const date_deb = "{{date_deb}}";
const date_fin = "{{date_fin}}";
{% if saisie_eval %}
createColumn(
date_deb,
date_fin,
{{ moduleimpl_id }}
);
window.location.href = "#saisie_eval"
getAndUpdateCol(1)
{% else %}
createColumn(); createColumn();
{% endif %}
</script> </script>

View File

@ -278,7 +278,7 @@
currentDate = moment(currentDate).tz(TIMEZONE).format("YYYY-MM-DDTHH:mm"); currentDate = moment(currentDate).tz(TIMEZONE).format("YYYY-MM-DDTHH:mm");
} }
function createColumn(dateStart = "", dateEnd = "") { function createColumn(dateStart = "", dateEnd = "", moduleimpl_id = "") {
let table = document.getElementById("studentTable"); let table = document.getElementById("studentTable");
let th = document.createElement("div"); let th = document.createElement("div");
th.classList.add("th", "error"); th.classList.add("th", "error");
@ -343,6 +343,10 @@
editModuleImpl(sl); editModuleImpl(sl);
}) })
if (moduleimpl_id != "") {
sl.value = moduleimpl_id;
}
let rows = table.querySelector(".tbody").querySelectorAll(".tr"); let rows = table.querySelector(".tbody").querySelectorAll(".tr");
for (let i = 0; i < rows.length; i++) { for (let i = 0; i < rows.length; i++) {
let td = document.createElement("div"); let td = document.createElement("div");

View File

@ -1,7 +1,7 @@
import datetime import datetime
from flask import g, request, render_template from flask import g, request, render_template, flash
from flask import abort, url_for from flask import abort, url_for, redirect
from flask_login import current_user from flask_login import current_user
from app import db from app import db
@ -18,6 +18,7 @@ from app.models import (
Assiduite, Assiduite,
Departement, Departement,
FormSemestreInscription, FormSemestreInscription,
Evaluation,
) )
from app.views import assiduites_bp as bp from app.views import assiduites_bp as bp
from app.views import ScoData from app.views import ScoData
@ -203,6 +204,27 @@ def signal_assiduites_etud():
if etud.dept_id != g.scodoc_dept_id: if etud.dept_id != g.scodoc_dept_id:
abort(404, "étudiant inexistant dans ce département") abort(404, "étudiant inexistant dans ce département")
date = request.args.get("date", datetime.date.today().isoformat())
# gestion évaluations
saisie_eval: bool = request.args.get("saisie_eval") is not None
date_deb: str = request.args.get("date_deb")
date_fin: str = request.args.get("date_fin")
moduleimpl_id: int = request.args.get("moduleimpl_id", "")
evaluation_id: int = request.args.get("evaluation_id")
redirect_url: str = (
"#"
if not saisie_eval
else url_for(
"notes.evaluation_check_absences_html",
evaluation_id=evaluation_id,
scodoc_dept=g.scodoc_dept,
)
)
header: str = html_sco_header.sco_header( header: str = html_sco_header.sco_header(
page_title="Saisie Assiduités", page_title="Saisie Assiduités",
init_qtip=True, init_qtip=True,
@ -235,7 +257,7 @@ def signal_assiduites_etud():
render_template( render_template(
"assiduites/pages/signal_assiduites_etud.j2", "assiduites/pages/signal_assiduites_etud.j2",
sco=ScoData(etud), sco=ScoData(etud),
date=datetime.date.today().isoformat(), date=date,
morning=morning, morning=morning,
lunch=lunch, lunch=lunch,
timeline=_timeline(), timeline=_timeline(),
@ -249,6 +271,11 @@ def signal_assiduites_etud():
etudiants=[sco_etud.get_etud_info(etudid=etud.etudid, filled=True)[0]], etudiants=[sco_etud.get_etud_info(etudid=etud.etudid, filled=True)[0]],
moduleimpl_select=select, moduleimpl_select=select,
), ),
saisie_eval=saisie_eval,
date_deb=date_deb,
date_fin=date_fin,
redirect_url=redirect_url,
moduleimpl_id=moduleimpl_id,
), ),
).build() ).build()
@ -995,6 +1022,66 @@ def signal_assiduites_diff():
).build() ).build()
@bp.route("/SignalEvaluationAbs/<int:evaluation_id>/<int:etudid>")
@scodoc
@permission_required(Permission.ScoView)
def signal_evaluation_abs(etudid: int = None, evaluation_id: int = None):
"""
Signale l'absence d'un étudiant à une évaluation
Si la durée de l'évaluation est inférieur à 1 jour
Alors l'absence sera sur la période de l'évaluation
Sinon L'utilisateur sera redirigé vers la page de saisie des absences de l'étudiant
"""
etud: Identite = Identite.query.get_or_404(etudid)
if etud.dept_id != g.scodoc_dept_id:
abort(404, "étudiant inexistant dans ce département")
evaluation: Evaluation = Evaluation.query.get_or_404(evaluation_id)
delta: datetime.timedelta = evaluation.date_fin - evaluation.date_debut
if delta > datetime.timedelta(days=1):
# rediriger vers page saisie
flash("Redirection pour saisie abs")
return redirect(
url_for(
"assiduites.signal_assiduites_etud",
etudid=etudid,
evaluation_id=evaluation.id,
date_deb=evaluation.date_debut.strftime("%Y-%m-%dT%H:%M:%S"),
date_fin=evaluation.date_fin.strftime("%Y-%m-%dT%H:%M:%S"),
moduleimpl_id=evaluation.moduleimpl.id,
saisie_eval="true",
scodoc_dept=g.scodoc_dept,
)
)
# créer l'assiduité
assiduite_unique: Assiduite = Assiduite.create_assiduite(
etud=etud,
date_debut=scu.localize_datetime(evaluation.date_debut),
date_fin=scu.localize_datetime(evaluation.date_fin),
etat=scu.EtatAssiduite.ABSENT,
moduleimpl=evaluation.moduleimpl,
)
db.session.add(assiduite_unique)
db.session.commit()
flash("L'absence a bien été créée")
# rediriger vers la page d'évaluation
return redirect(
url_for(
"notes.evaluation_check_absences_html",
evaluation_id=evaluation.id,
scodoc_dept=g.scodoc_dept,
)
)
# --- Fonctions internes ---
def _get_days_between_dates(deb: str, fin: str): def _get_days_between_dates(deb: str, fin: str):
if deb is None or fin is None: if deb is None or fin is None:
return "null" return "null"