Compare commits

...

6 Commits

13 changed files with 261 additions and 105 deletions

View File

@ -269,13 +269,7 @@ def validation_rcue_record(etudid: int):
validation.parcours_id = parcours_id validation.parcours_id = parcours_id
validation.ue1_id = ue1_id validation.ue1_id = ue1_id
validation.ue2_id = ue2_id validation.ue2_id = ue2_id
log(f"updating {validation}") operation = "update"
Scolog.logdb(
method="validation_rcue_record",
etudid=etudid,
msg=f"Mise à jour {validation}",
commit=False,
)
else: else:
validation = ApcValidationRCUE( validation = ApcValidationRCUE(
code=code, code=code,
@ -286,15 +280,16 @@ def validation_rcue_record(etudid: int):
ue1_id=ue1_id, ue1_id=ue1_id,
ue2_id=ue2_id, ue2_id=ue2_id,
) )
log(f"recording {validation}") operation = "record"
Scolog.logdb(
method="validation_rcue_record",
etudid=etudid,
msg=f"Enregistrement {validation}",
commit=False,
)
db.session.add(validation) db.session.add(validation)
db.session.commit() db.session.commit()
Scolog.logdb(
method="validation_rcue_record",
etudid=etudid,
msg=f"Enregistrement {validation}",
commit=True,
)
log(f"{operation} {validation}")
return validation.to_dict() return validation.to_dict()

View File

@ -212,6 +212,34 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
else: else:
self.ue_std_rows(rows, ue, title_bg) self.ue_std_rows(rows, ue, title_bg)
@staticmethod
def affichage_bonus_malus(ue: dict) -> list:
fields_bmr = []
# lecture des bonus sport culture et malus (ou bonus autre) (0 si valeur non numérique)
try:
bonus_sc = float(ue.get("bonus", 0.0)) or 0
except ValueError:
bonus_sc = 0
try:
malus = float(ue.get("malus", 0.0)) or 0
except ValueError:
malus = 0
# Calcul de l affichage
if malus < 0:
if bonus_sc > 0:
fields_bmr.append(f"Bonus sport/culture: {bonus_sc}")
fields_bmr.append(f"Bonus autres: {-malus}")
else:
fields_bmr.append(f"Bonus: {-malus}")
elif malus > 0:
if bonus_sc > 0:
fields_bmr.append(f"Bonus: {bonus_sc}")
fields_bmr.append(f"Malus: {malus}")
else:
if bonus_sc > 0:
fields_bmr.append(f"Bonus: {bonus_sc}")
return fields_bmr
def ue_std_rows(self, rows: list, ue: dict, title_bg: tuple): def ue_std_rows(self, rows: list, ue: dict, title_bg: tuple):
"Lignes décrivant une UE standard dans la table de synthèse" "Lignes décrivant une UE standard dans la table de synthèse"
# 2eme ligne titre UE (bonus/malus/ects) # 2eme ligne titre UE (bonus/malus/ects)
@ -220,20 +248,7 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
else: else:
ects_txt = "" ects_txt = ""
# case Bonus/Malus/Rang "bmr" # case Bonus/Malus/Rang "bmr"
fields_bmr = [] fields_bmr = BulletinGeneratorStandardBUT.affichage_bonus_malus(ue)
try:
value = float(ue.get("bonus", 0.0))
if value != 0:
fields_bmr.append(f"Bonus: {ue['bonus']}")
except ValueError:
pass
try:
value = float(ue.get("malus", 0.0))
if value != 0:
fields_bmr.append(f"Malus: {ue['malus']}")
except ValueError:
pass
moy_ue = ue.get("moyenne", "-") moy_ue = ue.get("moyenne", "-")
if isinstance(moy_ue, dict): # UE non capitalisées if isinstance(moy_ue, dict): # UE non capitalisées
if self.preferences["bul_show_ue_rangs"]: if self.preferences["bul_show_ue_rangs"]:

View File

@ -82,6 +82,10 @@ class ApcValidationRCUE(db.Model):
"as a dict" "as a dict"
d = dict(self.__dict__) d = dict(self.__dict__)
d.pop("_sa_instance_state", None) d.pop("_sa_instance_state", None)
d["etud"] = self.etud.to_dict_short()
d["ue1"] = self.ue1.to_dict()
d["ue2"] = self.ue2.to_dict()
return d return d
def to_dict_bul(self) -> dict: def to_dict_bul(self) -> dict:

View File

@ -33,7 +33,6 @@
import collections import collections
import datetime import datetime
import operator
import urllib import urllib
from urllib.parse import parse_qs from urllib.parse import parse_qs
import time import time
@ -42,6 +41,8 @@ import time
from flask import url_for, g, request from flask import url_for, g, request
from flask_login import current_user from flask_login import current_user
from app import db
from app.models import FormSemestre
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_abs from app.scodoc import sco_abs
@ -65,6 +66,7 @@ JAVASCRIPTS = html_sco_header.BOOTSTRAP_MULTISELECT_JS + [
CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS
# view: # view:
def groups_view( def groups_view(
group_ids=(), group_ids=(),
@ -422,6 +424,13 @@ class DisplayedGroupsInfos(object):
H.append(f'<input type="hidden" name="group_ids" value="{group_id}"/>') H.append(f'<input type="hidden" name="group_ids" value="{group_id}"/>')
return "\n".join(H) return "\n".join(H)
def get_formsemestre(self) -> FormSemestre:
return (
db.session.get(FormSemestre, self.formsemestre_id)
if self.formsemestre_id
else None
)
# Ancien ZScolar.group_list renommé ici en group_table # Ancien ZScolar.group_list renommé ici en group_table
def groups_table( def groups_table(

View File

@ -517,7 +517,7 @@ def ficheEtud(etudid=None):
cursus=but_cursus, cursus=but_cursus,
scu=scu, scu=scu,
)} )}
<div> <div class="link_validation_rcues">
<a href="{url_for("notes.validation_rcues", <a href="{url_for("notes.validation_rcues",
scodoc_dept=g.scodoc_dept, etudid=etudid, scodoc_dept=g.scodoc_dept, etudid=etudid,
formsemestre_id=last_formsemestre.id)}" formsemestre_id=last_formsemestre.id)}"

View File

@ -8,7 +8,7 @@
""" """
from flask import g, url_for from flask import g, url_for
from app.models import Identite, Assiduite, Justificatif from app.models import Identite, Justificatif
from app.tables import table_builder as tb from app.tables import table_builder as tb
import app.scodoc.sco_assiduites as scass import app.scodoc.sco_assiduites as scass
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
@ -65,31 +65,35 @@ class RowAssi(tb.Row):
} }
) )
bilan_etud = f"{url_for('assiduites.bilan_etud', scodoc_dept=g.scodoc_dept)}?etudid={etud.id}" bilan_etud = url_for(
"assiduites.bilan_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id
)
self.add_cell( self.add_cell(
"nom_disp", "nom_disp",
"Nom", "Nom",
etud.nom_disp(), etud.nom_disp(),
"identite_detail", "etudinfo",
attrs={"id": str(etud.id)},
data={"order": etud.sort_key}, data={"order": etud.sort_key},
target=bilan_etud, target=bilan_etud,
target_attrs={"class": "discretelink", "id": str(etud.id)}, target_attrs={"class": "discretelink"},
) )
self.add_cell( self.add_cell(
"prenom", "prenom",
"Prénom", "Prénom",
etud.prenom, etud.prenom_str,
"identite_detail", "etudinfo",
attrs={"id": str(etud.id)},
data={"order": etud.sort_key}, data={"order": etud.sort_key},
target=bilan_etud, target=bilan_etud,
target_attrs={"class": "discretelink", "id": str(etud.id)}, target_attrs={"class": "discretelink"},
) )
stats = self._get_etud_stats(etud) stats = self._get_etud_stats(etud)
for key, value in stats.items(): for key, value in stats.items():
self.add_cell(key, value[0], f"{value[1] - value[2]}", "assi_stats") self.add_cell(key, value[0], f"{value[1] - value[2]}", "assi_stats")
self.add_cell( self.add_cell(
key + "_justi", key + "_justi",
value[0] + " Justifiée(s)", value[0] + " Justifiées",
f"{value[2]}", f"{value[2]}",
"assi_stats", "assi_stats",
) )
@ -102,9 +106,9 @@ class RowAssi(tb.Row):
def _get_etud_stats(self, etud: Identite) -> dict[str, list[str, float, float]]: def _get_etud_stats(self, etud: Identite) -> dict[str, list[str, float, float]]:
retour: dict[str, tuple[str, float, float]] = { retour: dict[str, tuple[str, float, float]] = {
"present": ["Présence(s)", 0.0, 0.0], "present": ["Présences", 0.0, 0.0],
"retard": ["Retard(s)", 0.0, 0.0], "retard": ["Retards", 0.0, 0.0],
"absent": ["Absence(s)", 0.0, 0.0], "absent": ["Absences", 0.0, 0.0],
} }
assi_metric = { assi_metric = {

View File

@ -1,11 +1,22 @@
{% extends "sco_page.j2" %}
{% block scripts %}
{{ super() }}
<script src="{{scu.STATIC_DIR}}/js/etud_info.js"></script>
{% endblock %}
{% block app_content %}
<h2>Visualisation de l'assiduité {{gr_tit|safe}}</h2> <h2>Visualisation de l'assiduité {{gr_tit|safe}}</h2>
<div class="stats-inputs"> <div class="stats-inputs">
<label class="stats-label"> Date de début<input type="date" name="stats_date_debut" id="stats_date_debut" <label class="stats-label"> Date de début <input type="date" name="stats_date_debut" id="stats_date_debut"
value="{{date_debut}}"></label> value="{{date_debut}}"></label>
<label class="stats-label"> Date de fin<input type="date" name="stats_date_fin" id="stats_date_fin" <label class="stats-label"> Date de fin <input type="date" name="stats_date_fin" id="stats_date_fin"
value="{{date_fin}}"></label> value="{{date_fin}}"></label>
<button onclick="stats()">Changer la période</button> <button onclick="stats()">Changer</button>
<a style="margin-left:32px;" href="{{request.url}}&format=xlsx">{{scu.ICON_XLS|safe}}</a>
</div> </div>
{{tableau | safe}} {{tableau | safe}}
@ -26,4 +37,6 @@
document.querySelector('#stats_date_fin').value = date_fin; document.querySelector('#stats_date_fin').value = date_fin;
}) })
</script> </script>
{% endblock %}

View File

@ -100,6 +100,7 @@
data-ue2_id="{{niv['ue_pair'].id}}" data-ue2_id="{{niv['ue_pair'].id}}"
data-code="{{validation.code if validation else ''}}" data-code="{{validation.code if validation else ''}}"
> >
<option value="" disabled {{"selected" if not validation else ""}}>-</option>
{% for code in rcue_codes %} {% for code in rcue_codes %}
<option value="{{code}}" <option value="{{code}}"
{% if validation and validation.code == code -%} {% if validation and validation.code == code -%}

View File

@ -649,6 +649,7 @@ def visu_assi_group():
"debut": request.args.get("date_debut"), "debut": request.args.get("date_debut"),
"fin": request.args.get("date_fin"), "fin": request.args.get("date_fin"),
} }
fmt = request.args.get("format", "html")
group_ids: list[int] = request.args.get("group_ids", None) group_ids: list[int] = request.args.get("group_ids", None)
etudiants: list[dict] = [] etudiants: list[dict] = []
@ -662,14 +663,16 @@ def visu_assi_group():
groups_infos = sco_groups_view.DisplayedGroupsInfos(group_ids) groups_infos = sco_groups_view.DisplayedGroupsInfos(group_ids)
etuds = etuds_sorted_from_ids([m["etudid"] for m in groups_infos.members]) etuds = etuds_sorted_from_ids([m["etudid"] for m in groups_infos.members])
header: str = html_sco_header.sco_header(
page_title="Visualisation des assiduités",
init_qtip=True,
)
table: TableAssi = TableAssi(etuds=etuds, dates=list(dates.values())) table: TableAssi = TableAssi(etuds=etuds, dates=list(dates.values()))
if fmt.startswith("xls"):
return scu.send_file(
table.excel(),
filename=f"assiduite-{groups_infos.groups_filename}",
mime=scu.XLSX_MIMETYPE,
suffix=scu.XLSX_SUFFIX,
)
if groups_infos.tous_les_etuds_du_sem: if groups_infos.tous_les_etuds_du_sem:
gr_tit = "en" gr_tit = "en"
else: else:
@ -681,18 +684,16 @@ def visu_assi_group():
grp + ' <span class="fontred">' + groups_infos.groups_titles + "</span>" grp + ' <span class="fontred">' + groups_infos.groups_titles + "</span>"
) )
return HTMLBuilder( return render_template(
header, "assiduites/pages/visu_assi.j2",
render_template( tableau=table.html(),
"assiduites/pages/visu_assi.j2", gr_tit=gr_tit,
tableau=table.html(), date_debut=dates["debut"],
gr_tit=gr_tit, date_fin=dates["fin"],
date_debut=dates["debut"], group_ids=request.args.get("group_ids", None),
date_fin=dates["fin"], sco=ScoData(formsemestre=groups_infos.get_formsemestre()),
group_ids=request.args.get("group_ids", None), title=f"Assiduité {grp} {groups_infos.groups_titles}",
), )
html_sco_header.sco_footer(),
).build()
@bp.route("/SignalAssiduiteDifferee") @bp.route("/SignalAssiduiteDifferee")

View File

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

View File

@ -0,0 +1,82 @@
"""Tests unitaires : bulletins de notes
Utiliser comme:
pytest tests/unit/test_bulletin_bonus.py
"""
from app.but.bulletin_but_pdf import BulletinGeneratorStandardBUT
def test_nobonus():
assert BulletinGeneratorStandardBUT.affichage_bonus_malus({}) == []
def test_bonus_sport_nul():
assert BulletinGeneratorStandardBUT.affichage_bonus_malus({"bonus": 0}) == []
def test_malus_nul():
assert BulletinGeneratorStandardBUT.affichage_bonus_malus({"malus": 0}) == []
def test_bonus_et_malus_nuls():
assert (
BulletinGeneratorStandardBUT.affichage_bonus_malus({"bonus": 0, "malus": 0})
== []
)
def test_vrai_malus():
assert BulletinGeneratorStandardBUT.affichage_bonus_malus({"malus": 0.1}) == [
"Malus: 0.1"
]
def test_bonus_sport_et_vrai_malus():
assert BulletinGeneratorStandardBUT.affichage_bonus_malus(
{"malus": 0.12, "bonus": 0.23}
) == [
"Bonus: 0.23",
"Malus: 0.12",
]
def test_bonus_sport_seul():
assert BulletinGeneratorStandardBUT.affichage_bonus_malus({"bonus": 0.5}) == [
"Bonus: 0.5"
]
def test_bonus_sport_nul_et_vrai_malus():
assert BulletinGeneratorStandardBUT.affichage_bonus_malus(
{"bonus": 0, "malus": 0.5}
) == ["Malus: 0.5"]
def test_bonus_sport_et_malus_nul():
assert BulletinGeneratorStandardBUT.affichage_bonus_malus(
{"bonus": 0.5, "malus": 0}
) == [
"Bonus: 0.5",
]
def test_faux_malus():
assert BulletinGeneratorStandardBUT.affichage_bonus_malus({"malus": -0.6}) == [
"Bonus: 0.6"
]
def test_sport_nul_faux_malus():
assert BulletinGeneratorStandardBUT.affichage_bonus_malus(
{"bonus": 0, "malus": -0.6}
) == ["Bonus: 0.6"]
def test_bonus_sport_et_faux_malus():
assert BulletinGeneratorStandardBUT.affichage_bonus_malus(
{"bonus": 0.3, "malus": -0.6}
) == [
"Bonus sport/culture: 0.3",
"Bonus autres: 0.6",
]

View File

@ -75,9 +75,9 @@ fi
#echo "Creating python3 virtualenv..." #echo "Creating python3 virtualenv..."
su -c "(cd $SCODOC_DIR && python3 -m venv venv)" "$SCODOC_USER" || die "Error creating Python 3 virtualenv" su -c "(cd $SCODOC_DIR && python3 -m venv venv)" "$SCODOC_USER" || die "Error creating Python 3 virtualenv"
# ------------ INSTALL DES PAQUETS PYTHON (3.9) # ------------ INSTALL DES PAQUETS PYTHON (3.11)
# pip in our env, as user "scodoc" # pip in our env, as user "scodoc"
su -c "(cd $SCODOC_DIR && source venv/bin/activate && pip install wheel && pip install -r requirements-3.9.txt)" "$SCODOC_USER" || die "Error installing python packages" su -c "(cd $SCODOC_DIR && source venv/bin/activate && pip install wheel && pip install -r requirements-3.11.txt)" "$SCODOC_USER" || die "Error installing python packages"
# --- NGINX # --- NGINX
# Evite d'écraser: il faudrait ici présenter un dialogue "fichier local modifié, ..." # Evite d'écraser: il faudrait ici présenter un dialogue "fichier local modifié, ..."

View File

@ -7,6 +7,8 @@ from datetime import date, datetime, time, timedelta
from json import dump, dumps from json import dump, dumps
from sqlalchemy import not_ from sqlalchemy import not_
from flask import g
from app import db from app import db
from app.models import ( from app.models import (
Absence, Absence,
@ -30,6 +32,7 @@ from app.scodoc.sco_utils import (
localize_datetime, localize_datetime,
print_progress_bar, print_progress_bar,
) )
from app.scodoc import notesdb as ndb
class _glob: class _glob:
@ -38,7 +41,6 @@ class _glob:
DEBUG: bool = False DEBUG: bool = False
PROBLEMS: dict[int, list[str]] = {} PROBLEMS: dict[int, list[str]] = {}
DEPT_ETUDIDS: dict[int, Identite] = {} DEPT_ETUDIDS: dict[int, Identite] = {}
MODULES: dict[tuple[int, int]] = {}
COMPTE: list[int, int] = [] COMPTE: list[int, int] = []
ERR_ETU: list[int] = [] ERR_ETU: list[int] = []
MERGER_ASSI: "_Merger" = None MERGER_ASSI: "_Merger" = None
@ -97,42 +99,70 @@ class _Merger:
date_deb = _Merger._tuple_to_date(self.deb) date_deb = _Merger._tuple_to_date(self.deb)
date_fin = _Merger._tuple_to_date(self.fin, end=True) date_fin = _Merger._tuple_to_date(self.fin, end=True)
retour = Justificatif.fast_create_justificatif( _glob.cursor.execute(
etudid=self.etudid, """INSERT INTO justificatifs
date_debut=date_deb, (etudid,date_debut,date_fin,etat,raison,entry_date)
date_fin=date_fin, VALUES (%(etudid)s,%(date_debut)s,%(date_fin)s,%(etat)s,%(raison)s,%(entry_date)s)
etat=EtatJustificatif.VALIDE, """,
raison=self.raison, {
entry_date=self.entry_date, "etudid": self.etudid,
"date_debut": date_deb,
"date_fin": date_fin,
"etat": EtatJustificatif.VALIDE,
"raison": self.raison,
"entry_date": self.entry_date,
},
) )
return retour # retour = Justificatif.fast_create_justificatif(
# etudid=self.etudid,
# date_debut=date_deb,
# date_fin=date_fin,
# etat=EtatJustificatif.VALIDE,
# raison=self.raison,
# entry_date=self.entry_date,
# )
# return retour
def _to_assi(self): def _to_assi(self):
date_deb = _Merger._tuple_to_date(self.deb) date_deb = _Merger._tuple_to_date(self.deb)
date_fin = _Merger._tuple_to_date(self.fin, end=True) date_fin = _Merger._tuple_to_date(self.fin, end=True)
retour = Assiduite.fast_create_assiduite( _glob.cursor.execute(
etudid=self.etudid, """INSERT INTO assiduites
date_debut=date_deb, (etudid,date_debut,date_fin,etat,moduleimpl_id,"desc",entry_date)
date_fin=date_fin, VALUES (%(etudid)s,%(date_debut)s,%(date_fin)s,%(etat)s,%(moduleimpl_id)s,%(desc)s,%(entry_date)s)
etat=EtatAssiduite.ABSENT, """,
moduleimpl_id=self.moduleimpl, {
description=self.raison, "etudid": self.etudid,
entry_date=self.entry_date, "date_debut": date_deb,
"date_fin": date_fin,
"etat": EtatAssiduite.ABSENT,
"moduleimpl_id": self.moduleimpl,
"desc": self.raison,
"entry_date": self.entry_date,
},
) )
return retour
# retour = Assiduite.fast_create_assiduite(
# etudid=self.etudid,
# date_debut=date_deb,
# date_fin=date_fin,
# etat=EtatAssiduite.ABSENT,
# moduleimpl_id=self.moduleimpl,
# description=self.raison,
# entry_date=self.entry_date,
# )
# return retour
def export(self): def export(self):
"""Génère un nouvel objet Assiduité ou Justificatif""" """Génère un nouvel objet Assiduité ou Justificatif"""
obj: Assiduite or Justificatif = None obj: Assiduite or Justificatif = None
if self.est_abs: if self.est_abs:
_glob.COMPTE[0] += 1 _glob.COMPTE[0] += 1
obj = self._to_assi() self._to_assi()
else: else:
_glob.COMPTE[1] += 1 _glob.COMPTE[1] += 1
obj = self._to_justif() self._to_justif()
db.session.add(obj)
class _Statistics: class _Statistics:
@ -243,6 +273,10 @@ def migrate_abs_to_assiduites(
evening: list[str] = str(evening).split(":") evening: list[str] = str(evening).split(":")
_glob.EVENING = time(int(evening[0]), int(evening[1])) _glob.EVENING = time(int(evening[0]), int(evening[1]))
ndb.open_db_connection()
_glob.cnx = g.db_conn
_glob.cursor = _glob.cnx.cursor()
if dept is None: if dept is None:
prof_total = Profiler("MigrationTotal") prof_total = Profiler("MigrationTotal")
prof_total.start() prof_total.start()
@ -287,7 +321,6 @@ def migrate_dept(dept_name: str, stats: _Statistics, time_elapsed: Profiler):
return return
_glob.DEPT_ETUDIDS = {e.id for e in Identite.query.filter_by(dept_id=dept.id)} _glob.DEPT_ETUDIDS = {e.id for e in Identite.query.filter_by(dept_id=dept.id)}
_glob.MODULES = {}
_glob.COMPTE = [0, 0] _glob.COMPTE = [0, 0]
_glob.ERR_ETU = [] _glob.ERR_ETU = []
_glob.MERGER_ASSI = None _glob.MERGER_ASSI = None
@ -299,9 +332,17 @@ def migrate_dept(dept_name: str, stats: _Statistics, time_elapsed: Profiler):
print_progress_bar(0, absences_len, "Progression", "effectué", autosize=True) print_progress_bar(0, absences_len, "Progression", "effectué", autosize=True)
etuds_modimpl_ids = {}
for i, abs_ in enumerate(absences): for i, abs_ in enumerate(absences):
etud_modimpl_ids = etuds_modimpl_ids.get(abs_.etudid)
if etud_modimpl_ids is None:
etud_modimpl_ids = {
ins.moduleimpl_id
for ins in ModuleImplInscription.query.filter_by(etudid=abs_.etudid)
}
etuds_modimpl_ids[abs_.etudid] = etud_modimpl_ids
try: try:
_from_abs_to_assiduite_justificatif(abs_) _from_abs_to_assiduite_justificatif(abs_, etud_modimpl_ids)
except ValueError as e: except ValueError as e:
stats.add_problem(abs_, e.args[0]) stats.add_problem(abs_, e.args[0])
@ -322,14 +363,14 @@ def migrate_dept(dept_name: str, stats: _Statistics, time_elapsed: Profiler):
"effectué", "effectué",
autosize=True, autosize=True,
) )
db.session.commit() _glob.cnx.commit()
if _glob.MERGER_ASSI is not None: if _glob.MERGER_ASSI is not None:
_glob.MERGER_ASSI.export() _glob.MERGER_ASSI.export()
if _glob.MERGER_JUST is not None: if _glob.MERGER_JUST is not None:
_glob.MERGER_JUST.export() _glob.MERGER_JUST.export()
db.session.commit() _glob.cnx.commit()
print_progress_bar( print_progress_bar(
absences_len, absences_len,
@ -379,24 +420,15 @@ def migrate_dept(dept_name: str, stats: _Statistics, time_elapsed: Profiler):
print(dumps(statistiques, indent=2)) print(dumps(statistiques, indent=2))
def _from_abs_to_assiduite_justificatif(_abs: Absence): def _from_abs_to_assiduite_justificatif(_abs: Absence, etud_modimpl_ids: set[int]):
if _abs.etudid not in _glob.DEPT_ETUDIDS: if _abs.etudid not in _glob.DEPT_ETUDIDS:
raise ValueError("Etudiant inexistant") raise ValueError("Etudiant inexistant")
if _abs.estabs: if _abs.estabs:
moduleimpl_id: int = _abs.moduleimpl_id if (_abs.moduleimpl_id is not None) and (
if ( _abs.moduleimpl_id not in etud_modimpl_ids
moduleimpl_id is not None
and (_abs.etudid, _abs.moduleimpl_id) not in _glob.MODULES
): ):
moduleimpl_inscription: ModuleImplInscription = ( raise ValueError("Moduleimpl_id incorrect ou étudiant non inscrit")
ModuleImplInscription.query.filter_by(
moduleimpl_id=_abs.moduleimpl_id, etudid=_abs.etudid
).first()
)
if moduleimpl_inscription is None:
raise ValueError("Moduleimpl_id incorrect ou étudiant non inscrit")
_glob.MODULES[(_abs.etudid, _abs.moduleimpl_id)] = True
if _glob.MERGER_ASSI is None: if _glob.MERGER_ASSI is None:
_glob.MERGER_ASSI = _Merger(_abs, True) _glob.MERGER_ASSI = _Merger(_abs, True)