script migration abs -> assiduites (WIP)
This commit is contained in:
parent
095eb6ce20
commit
c11599b64f
@ -15,8 +15,10 @@ class Absence(db.Model):
|
||||
db.Integer, db.ForeignKey("identite.id", ondelete="CASCADE"), index=True
|
||||
)
|
||||
jour = db.Column(db.Date)
|
||||
# absent / justifié / absent+ justifié
|
||||
estabs = db.Column(db.Boolean())
|
||||
estjust = db.Column(db.Boolean())
|
||||
|
||||
matin = db.Column(db.Boolean())
|
||||
# motif de l'absence:
|
||||
description = db.Column(db.Text())
|
||||
|
@ -77,6 +77,7 @@ class Assiduite(db.Model):
|
||||
etat: EtatAssiduite,
|
||||
moduleimpl: ModuleImpl = None,
|
||||
description: str = None,
|
||||
entry_date: datetime = None,
|
||||
) -> object or int:
|
||||
"""Créer une nouvelle assiduité pour l'étudiant"""
|
||||
# Vérification de non duplication des périodes
|
||||
@ -97,6 +98,7 @@ class Assiduite(db.Model):
|
||||
etudiant=etud,
|
||||
moduleimpl_id=moduleimpl.id,
|
||||
desc=description,
|
||||
entry_date=entry_date,
|
||||
)
|
||||
else:
|
||||
raise ScoValueError("L'étudiant n'est pas inscrit au moduleimpl")
|
||||
@ -107,6 +109,7 @@ class Assiduite(db.Model):
|
||||
etat=etat,
|
||||
etudiant=etud,
|
||||
desc=description,
|
||||
entry_date=entry_date,
|
||||
)
|
||||
|
||||
return nouv_assiduite
|
||||
@ -178,6 +181,7 @@ class Justificatif(db.Model):
|
||||
date_fin: datetime,
|
||||
etat: EtatJustificatif,
|
||||
raison: str = None,
|
||||
entry_date: datetime = None,
|
||||
) -> object or int:
|
||||
"""Créer un nouveau justificatif pour l'étudiant"""
|
||||
# Vérification de non duplication des périodes
|
||||
@ -193,6 +197,7 @@ class Justificatif(db.Model):
|
||||
etat=etat,
|
||||
etudiant=etud,
|
||||
raison=raison,
|
||||
entry_date=entry_date,
|
||||
)
|
||||
|
||||
return nouv_justificatif
|
||||
@ -214,8 +219,7 @@ def is_period_conflicting(
|
||||
uni
|
||||
for uni in collection
|
||||
if is_period_overlapping(
|
||||
(date_debut, date_fin),
|
||||
(uni.date_debut, uni.date_fin),
|
||||
(date_debut, date_fin), (uni.date_debut, uni.date_fin), bornes=False
|
||||
)
|
||||
]
|
||||
|
||||
|
@ -42,6 +42,8 @@ from app.scodoc import sco_cache
|
||||
from app.scodoc import sco_etud
|
||||
from app.scodoc import sco_formsemestre_inscriptions
|
||||
from app.scodoc import sco_preferences
|
||||
from app.models import Assiduite
|
||||
import app.scodoc.sco_assiduites as scass
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
||||
# --- Misc tools.... ------------------
|
||||
@ -1026,7 +1028,7 @@ def get_abs_count(etudid, sem):
|
||||
"""
|
||||
return get_abs_count_in_interval(etudid, sem["date_debut_iso"], sem["date_fin_iso"])
|
||||
|
||||
# TODO: relier avec module assiduites
|
||||
|
||||
def get_abs_count_in_interval(etudid, date_debut_iso, date_fin_iso):
|
||||
"""Les comptes d'absences de cet étudiant entre ces deux dates, incluses:
|
||||
tuple (nb abs, nb abs justifiées)
|
||||
@ -1052,6 +1054,36 @@ def get_abs_count_in_interval(etudid, date_debut_iso, date_fin_iso):
|
||||
return r
|
||||
|
||||
|
||||
def get_assiduites_count_in_interval(etudid, date_debut_iso, date_fin_iso):
|
||||
"""Les comptes d'absences de cet étudiant entre ces deux dates, incluses:
|
||||
tuple (nb abs, nb abs justifiées)
|
||||
Utilise un cache.
|
||||
"""
|
||||
key = str(etudid) + "_" + date_debut_iso + "_" + date_fin_iso
|
||||
r = sco_cache.AbsSemEtudCache.get(key)
|
||||
if not r:
|
||||
|
||||
date_debut: datetime.datetime = scu.is_iso_formated(date_debut_iso, True)
|
||||
date_fin: datetime.datetime = scu.is_iso_formated(date_debut_iso, True)
|
||||
|
||||
assiduites: Assiduite = Assiduite.query.filter_by(etudid=etudid)
|
||||
|
||||
assiduites = scass.filter_assiduites_by_date(assiduites, date_debut, sup=True)
|
||||
assiduites = scass.filter_assiduites_by_date(assiduites, date_fin, sup=False)
|
||||
|
||||
nb_abs = scass.get_count(assiduites)["demi"]
|
||||
nb_abs_just = count_abs_just(
|
||||
etudid=etudid,
|
||||
debut=date_debut_iso,
|
||||
fin=date_fin_iso,
|
||||
)
|
||||
r = (nb_abs, nb_abs_just)
|
||||
ans = sco_cache.AbsSemEtudCache.set(key, r)
|
||||
if not ans:
|
||||
log("warning: get_abs_count failed to cache")
|
||||
return r
|
||||
|
||||
|
||||
def invalidate_abs_count(etudid, sem):
|
||||
"""Invalidate (clear) cached counts"""
|
||||
date_debut = sem["date_debut_iso"]
|
||||
|
@ -174,7 +174,7 @@ def localize_datetime(date: datetime.datetime or str) -> datetime.datetime:
|
||||
def is_period_overlapping(
|
||||
periode: tuple[datetime.datetime, datetime.datetime],
|
||||
interval: tuple[datetime.datetime, datetime.datetime],
|
||||
strict: bool = True,
|
||||
bornes: bool = True,
|
||||
) -> bool:
|
||||
"""
|
||||
Vérifie si la période et l'interval s'intersectent
|
||||
@ -184,7 +184,7 @@ def is_period_overlapping(
|
||||
p_deb, p_fin = periode
|
||||
i_deb, i_fin = interval
|
||||
|
||||
if not strict:
|
||||
if bornes:
|
||||
return p_deb <= i_fin and p_fin >= i_deb
|
||||
return p_deb < i_fin and p_fin > i_deb
|
||||
|
||||
|
13
scodoc.py
13
scodoc.py
@ -470,6 +470,19 @@ def migrate_scodoc7_dept_archives(dept: str): # migrate-scodoc7-dept-archives
|
||||
tools.migrate_scodoc7_dept_archives(dept)
|
||||
|
||||
|
||||
@app.cli.command()
|
||||
@click.argument("dept", default="")
|
||||
@click.argument("morning", default="")
|
||||
@click.argument("noon", default="")
|
||||
@click.argument("evening", default="")
|
||||
@with_appcontext
|
||||
def migrate_abs_to_assiduites(
|
||||
dept: str = "", morning: str = "", noon: str = "", evening: str = ""
|
||||
): # migrate-scodoc7-dept-archives
|
||||
"""Post-migration: renomme les archives en fonction des id de ScoDoc 9"""
|
||||
tools.migrate_abs_to_assiduites(dept, morning, noon, evening)
|
||||
|
||||
|
||||
@app.cli.command()
|
||||
@click.argument("dept", default="")
|
||||
@with_appcontext
|
||||
|
@ -8,3 +8,4 @@ from tools.import_scodoc7_user_db import import_scodoc7_user_db
|
||||
from tools.import_scodoc7_dept import import_scodoc7_dept
|
||||
from tools.migrate_scodoc7_archives import migrate_scodoc7_dept_archives
|
||||
from tools.migrate_scodoc7_logos import migrate_scodoc7_dept_logos
|
||||
from tools.migrate_abs_to_assiduites import migrate_abs_to_assiduites
|
||||
|
173
tools/migrate_abs_to_assiduites.py
Normal file
173
tools/migrate_abs_to_assiduites.py
Normal file
@ -0,0 +1,173 @@
|
||||
# Script de migration des données de la base "absences" -> "assiduites"/"justificatifs"
|
||||
|
||||
from app import db
|
||||
|
||||
from app.models import (
|
||||
Assiduite,
|
||||
Justificatif,
|
||||
Absence,
|
||||
Identite,
|
||||
ModuleImpl,
|
||||
Departement,
|
||||
)
|
||||
from app.scodoc.sco_utils import EtatAssiduite, EtatJustificatif, localize_datetime
|
||||
from datetime import time, datetime, date
|
||||
|
||||
|
||||
class glob:
|
||||
DUPLICATIONS_ASSIDUITES: dict[tuple[date, bool, int], Assiduite] = {}
|
||||
DUPLICATED: list[Justificatif] = []
|
||||
|
||||
|
||||
def migrate_abs_to_assiduites(
|
||||
dept: str = "", morning: str = None, noon: str = None, evening: str = None
|
||||
):
|
||||
"""
|
||||
une absence à 3 états:
|
||||
|
||||
|.estabs|.estjust|
|
||||
|1|0| -> absence non justifiée
|
||||
|1|1| -> absence justifiée
|
||||
|0|1| -> justifié
|
||||
|
||||
dualité des temps :
|
||||
|
||||
.matin: bool (0:00 -> time_pref | time_pref->23:59:59)
|
||||
.jour : date (jour de l'absence/justificatif)
|
||||
.moduleimpl_id: relation -> moduleimpl_id
|
||||
description:str -> motif abs / raision justif
|
||||
|
||||
.entry_date: datetime -> timestamp d'entrée de l'abs
|
||||
.etudid: relation -> Identite
|
||||
"""
|
||||
if morning == "":
|
||||
pref_time_morning = time(8, 0)
|
||||
else:
|
||||
morning: list[str] = morning.split("h")
|
||||
pref_time_morning = time(int(morning[0]), int(morning[1]))
|
||||
|
||||
if noon == "":
|
||||
pref_time_noon = time(12, 0)
|
||||
else:
|
||||
noon: list[str] = noon.split("h")
|
||||
pref_time_noon = time(int(noon[0]), int(noon[1]))
|
||||
|
||||
if evening == "":
|
||||
pref_time_evening = time(18, 0)
|
||||
else:
|
||||
evening: list[str] = evening.split("h")
|
||||
pref_time_evening = time(int(evening[0]), int(evening[1]))
|
||||
|
||||
absences_query = Absence.query
|
||||
if dept != "":
|
||||
depts_id = [dep.id for dep in Departement.query.filter_by(acronym=dept).all()]
|
||||
absences_query = absences_query.filter(Absence.etudid.in_(depts_id))
|
||||
absences: list[Absence] = absences_query.order_by(Absence.jour).all()
|
||||
|
||||
glob.DUPLICATED = []
|
||||
glob.DUPLICATIONS_ASSIDUITES = {}
|
||||
|
||||
for abs in absences:
|
||||
print(f"\n== {abs.jour}:{abs.etudid}:{abs.matin} ==")
|
||||
if abs.estabs:
|
||||
generated = _from_abs_to_assiduite(
|
||||
abs, pref_time_morning, pref_time_noon, pref_time_evening
|
||||
)
|
||||
if not isinstance(generated, str):
|
||||
db.session.add(generated)
|
||||
print(
|
||||
f"{abs.jour}:absence:{abs.etudid}:{abs.matin} -> {generated.date_debut}:{generated.date_fin}"
|
||||
)
|
||||
if abs.estjust:
|
||||
generated = _from_abs_to_justificatif(
|
||||
abs, pref_time_morning, pref_time_noon, pref_time_evening
|
||||
)
|
||||
if not isinstance(generated, str):
|
||||
db.session.add(generated)
|
||||
print(
|
||||
f"{abs.jour}:justif:{abs.etudid}:{abs.matin} -> {generated.date_debut}:{generated.date_fin}"
|
||||
)
|
||||
|
||||
dup_assi = glob.DUPLICATED
|
||||
assi: Assiduite
|
||||
for assi in dup_assi:
|
||||
assi.moduleimpl_id = None
|
||||
db.session.add(assi)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def _from_abs_to_assiduite(
|
||||
_abs: Absence, morning: time, noon: time, evening: time
|
||||
) -> Assiduite:
|
||||
etat = EtatAssiduite.ABSENT
|
||||
date_deb: datetime = None
|
||||
date_fin: datetime = None
|
||||
if _abs.matin:
|
||||
date_deb = datetime.combine(_abs.jour, morning)
|
||||
date_fin = datetime.combine(_abs.jour, noon)
|
||||
else:
|
||||
date_deb = datetime.combine(_abs.jour, noon)
|
||||
date_fin = datetime.combine(_abs.jour, evening)
|
||||
|
||||
date_deb = localize_datetime(date_deb)
|
||||
date_fin = localize_datetime(date_fin)
|
||||
duplicata: Assiduite = glob.DUPLICATIONS_ASSIDUITES.get(
|
||||
(_abs.jour, _abs.matin, _abs.etudid)
|
||||
)
|
||||
if duplicata is not None:
|
||||
glob.DUPLICATED.append(duplicata)
|
||||
return "Duplicated"
|
||||
|
||||
desc: str = _abs.description
|
||||
entry_date: datetime = _abs.entry_date
|
||||
|
||||
etud: Identite = Identite.query.filter_by(id=_abs.etudid).first()
|
||||
moduleimpl: ModuleImpl = ModuleImpl.query.filter_by(id=_abs.moduleimpl_id).first()
|
||||
|
||||
retour = Assiduite.create_assiduite(
|
||||
etud=etud,
|
||||
date_debut=date_deb,
|
||||
date_fin=date_fin,
|
||||
etat=etat,
|
||||
moduleimpl=moduleimpl,
|
||||
description=desc,
|
||||
entry_date=entry_date,
|
||||
)
|
||||
|
||||
glob.DUPLICATIONS_ASSIDUITES[(_abs.jour, _abs.matin, _abs.etudid)] = retour
|
||||
|
||||
return retour
|
||||
|
||||
|
||||
def _from_abs_to_justificatif(
|
||||
_abs: Absence, morning: time, noon: time, evening: time
|
||||
) -> Justificatif:
|
||||
etat = EtatJustificatif.VALIDE
|
||||
date_deb: datetime = None
|
||||
date_fin: datetime = None
|
||||
if _abs.matin:
|
||||
date_deb = datetime.combine(_abs.jour, morning)
|
||||
date_fin = datetime.combine(_abs.jour, noon)
|
||||
else:
|
||||
date_deb = datetime.combine(_abs.jour, noon)
|
||||
date_fin = datetime.combine(_abs.jour, evening)
|
||||
|
||||
date_deb = localize_datetime(date_deb)
|
||||
date_fin = localize_datetime(date_fin)
|
||||
|
||||
desc: str = _abs.description
|
||||
entry_date: datetime = _abs.entry_date
|
||||
|
||||
etud: Identite = Identite.query.filter_by(id=_abs.etudid).first()
|
||||
|
||||
retour = Justificatif.create_justificatif(
|
||||
etud=etud,
|
||||
date_debut=date_deb,
|
||||
date_fin=date_fin,
|
||||
etat=etat,
|
||||
raison=desc,
|
||||
entry_date=entry_date,
|
||||
)
|
||||
|
||||
return retour
|
Loading…
Reference in New Issue
Block a user