forked from ScoDoc/ScoDoc
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
|
db.Integer, db.ForeignKey("identite.id", ondelete="CASCADE"), index=True
|
||||||
)
|
)
|
||||||
jour = db.Column(db.Date)
|
jour = db.Column(db.Date)
|
||||||
|
# absent / justifié / absent+ justifié
|
||||||
estabs = db.Column(db.Boolean())
|
estabs = db.Column(db.Boolean())
|
||||||
estjust = db.Column(db.Boolean())
|
estjust = db.Column(db.Boolean())
|
||||||
|
|
||||||
matin = db.Column(db.Boolean())
|
matin = db.Column(db.Boolean())
|
||||||
# motif de l'absence:
|
# motif de l'absence:
|
||||||
description = db.Column(db.Text())
|
description = db.Column(db.Text())
|
||||||
|
@ -77,6 +77,7 @@ class Assiduite(db.Model):
|
|||||||
etat: EtatAssiduite,
|
etat: EtatAssiduite,
|
||||||
moduleimpl: ModuleImpl = None,
|
moduleimpl: ModuleImpl = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
|
entry_date: datetime = None,
|
||||||
) -> object or int:
|
) -> object or int:
|
||||||
"""Créer une nouvelle assiduité pour l'étudiant"""
|
"""Créer une nouvelle assiduité pour l'étudiant"""
|
||||||
# Vérification de non duplication des périodes
|
# Vérification de non duplication des périodes
|
||||||
@ -97,6 +98,7 @@ class Assiduite(db.Model):
|
|||||||
etudiant=etud,
|
etudiant=etud,
|
||||||
moduleimpl_id=moduleimpl.id,
|
moduleimpl_id=moduleimpl.id,
|
||||||
desc=description,
|
desc=description,
|
||||||
|
entry_date=entry_date,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ScoValueError("L'étudiant n'est pas inscrit au moduleimpl")
|
raise ScoValueError("L'étudiant n'est pas inscrit au moduleimpl")
|
||||||
@ -107,6 +109,7 @@ class Assiduite(db.Model):
|
|||||||
etat=etat,
|
etat=etat,
|
||||||
etudiant=etud,
|
etudiant=etud,
|
||||||
desc=description,
|
desc=description,
|
||||||
|
entry_date=entry_date,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nouv_assiduite
|
return nouv_assiduite
|
||||||
@ -178,6 +181,7 @@ class Justificatif(db.Model):
|
|||||||
date_fin: datetime,
|
date_fin: datetime,
|
||||||
etat: EtatJustificatif,
|
etat: EtatJustificatif,
|
||||||
raison: str = None,
|
raison: str = None,
|
||||||
|
entry_date: datetime = None,
|
||||||
) -> object or int:
|
) -> object or int:
|
||||||
"""Créer un nouveau justificatif pour l'étudiant"""
|
"""Créer un nouveau justificatif pour l'étudiant"""
|
||||||
# Vérification de non duplication des périodes
|
# Vérification de non duplication des périodes
|
||||||
@ -193,6 +197,7 @@ class Justificatif(db.Model):
|
|||||||
etat=etat,
|
etat=etat,
|
||||||
etudiant=etud,
|
etudiant=etud,
|
||||||
raison=raison,
|
raison=raison,
|
||||||
|
entry_date=entry_date,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nouv_justificatif
|
return nouv_justificatif
|
||||||
@ -214,8 +219,7 @@ def is_period_conflicting(
|
|||||||
uni
|
uni
|
||||||
for uni in collection
|
for uni in collection
|
||||||
if is_period_overlapping(
|
if is_period_overlapping(
|
||||||
(date_debut, date_fin),
|
(date_debut, date_fin), (uni.date_debut, uni.date_fin), bornes=False
|
||||||
(uni.date_debut, uni.date_fin),
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -42,6 +42,8 @@ from app.scodoc import sco_cache
|
|||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
from app.scodoc import sco_formsemestre_inscriptions
|
from app.scodoc import sco_formsemestre_inscriptions
|
||||||
from app.scodoc import sco_preferences
|
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
|
import app.scodoc.sco_utils as scu
|
||||||
|
|
||||||
# --- Misc tools.... ------------------
|
# --- 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"])
|
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):
|
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:
|
"""Les comptes d'absences de cet étudiant entre ces deux dates, incluses:
|
||||||
tuple (nb abs, nb abs justifiées)
|
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
|
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):
|
def invalidate_abs_count(etudid, sem):
|
||||||
"""Invalidate (clear) cached counts"""
|
"""Invalidate (clear) cached counts"""
|
||||||
date_debut = sem["date_debut_iso"]
|
date_debut = sem["date_debut_iso"]
|
||||||
|
@ -174,7 +174,7 @@ def localize_datetime(date: datetime.datetime or str) -> datetime.datetime:
|
|||||||
def is_period_overlapping(
|
def is_period_overlapping(
|
||||||
periode: tuple[datetime.datetime, datetime.datetime],
|
periode: tuple[datetime.datetime, datetime.datetime],
|
||||||
interval: tuple[datetime.datetime, datetime.datetime],
|
interval: tuple[datetime.datetime, datetime.datetime],
|
||||||
strict: bool = True,
|
bornes: bool = True,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Vérifie si la période et l'interval s'intersectent
|
Vérifie si la période et l'interval s'intersectent
|
||||||
@ -184,7 +184,7 @@ def is_period_overlapping(
|
|||||||
p_deb, p_fin = periode
|
p_deb, p_fin = periode
|
||||||
i_deb, i_fin = interval
|
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
|
||||||
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)
|
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()
|
@app.cli.command()
|
||||||
@click.argument("dept", default="")
|
@click.argument("dept", default="")
|
||||||
@with_appcontext
|
@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.import_scodoc7_dept import import_scodoc7_dept
|
||||||
from tools.migrate_scodoc7_archives import migrate_scodoc7_dept_archives
|
from tools.migrate_scodoc7_archives import migrate_scodoc7_dept_archives
|
||||||
from tools.migrate_scodoc7_logos import migrate_scodoc7_dept_logos
|
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