from datetime import date, datetime, time, timedelta import app.scodoc.sco_utils as scu from app.models.assiduites import Assiduite from app.models.etudiants import Identite from app.models.formsemestre import FormSemestre, FormSemestreInscription # TOTALK: Réfléchir sur le fractionnement d'une assiduite prolongée def get_assiduites_stats( assiduites: Assiduite, metric: str = "all", filtered: dict[str, object] = None ) -> Assiduite: if filtered is not None: for key in filtered: if key == "etat": assiduites = filter_by_etat(assiduites, filtered[key]) elif key == "date_fin": assiduites = filter_by_date(assiduites, filtered[key], sup=False) elif key == "date_debut": assiduites = filter_by_date(assiduites, filtered[key], sup=True) elif key == "moduleimpl_id": assiduites = filter_by_module_impl(assiduites, filtered[key]) elif key == "formsemestre": assiduites = filter_by_formsemestre(assiduites, filtered[key]) count: dict = get_count(assiduites) metrics: list[str] = metric.split(",") output: dict = {} for key, val in count.items(): if key in metrics: output[key] = val return output if output else count def get_count(assiduites: Assiduite) -> dict[str, int or float]: output: dict[str, int or float] = {} output["compte"] = assiduites.count() output["heure"] = 0.0 output["journee"] = 0 output["demi"] = 0 all_assiduites: list[Assiduite] = assiduites.order_by(Assiduite.date_debut).all() current_day: date = None current_time: str = None midnight: time = time(hour=0) noon: time = time(hour=12) def time_check(dtime): return midnight <= dtime.time() <= noon for ass in all_assiduites: delta: timedelta = ass.date_fin - ass.date_debut output["heure"] += delta.total_seconds() / 3600 ass_time: str = time_check(ass.date_debut) if current_day != ass.date_debut.date(): current_day = ass.date_debut.date() current_time = ass_time output["demi"] += 1 output["journee"] += 1 if current_time != ass_time: current_time = ass_time output["demi"] += 1 output["heure"] = round(output["heure"], 2) return output def filter_by_etat(assiduites: Assiduite, etat: str) -> Assiduite: """ Filtrage d'une collection d'assiduites en fonction de leur état """ etats: list[str] = list(etat.split(",")) etats = [scu.ETATS_ASSIDUITE.get(e, -1) for e in etats] return assiduites.filter(Assiduite.etat.in_(etats)) def filter_by_date( assiduites: Assiduite, date_: datetime, sup: bool = True ) -> Assiduite: """ Filtrage d'une collection d'assiduites en fonction d'une date Sup == True -> les assiduites doivent débuter après 'date'\n Sup == False -> les assiduites doivent finir avant 'date' """ if date_.tzinfo is None: first_assiduite: Assiduite = assiduites.first() if first_assiduite is not None: date_: datetime = date_.replace(tzinfo=first_assiduite.date_debut.tzinfo) if sup: return assiduites.filter(Assiduite.date_debut >= date_) return assiduites.filter(Assiduite.date_fin <= date_) def filter_by_module_impl( assiduites: Assiduite, module_impl_id: int or None ) -> Assiduite: """ Filtrage d'une collection d'assiduites en fonction de l'ID du module_impl """ return assiduites.filter(Assiduite.moduleimpl_id == module_impl_id) def filter_by_formsemestre(assiduites_query: Assiduite, formsemestre: FormSemestre): """ Filtrage d'une collection d'assiduites en fonction d'un formsemestre """ if formsemestre is None: return assiduites_query.filter(False) assiduites_query = ( assiduites_query.join(Identite, Assiduite.etudid == Identite.id) .join( FormSemestreInscription, Identite.id == FormSemestreInscription.etudid, ) .filter(FormSemestreInscription.formsemestre_id == formsemestre.id) ) assiduites_query = assiduites_query.filter( Assiduite.date_debut >= formsemestre.date_debut ) return assiduites_query.filter(Assiduite.date_fin <= formsemestre.date_fin)