forked from ScoDoc/DocScoDoc
WIP: paramétrage dates antipodiques
This commit is contained in:
parent
836c57ec98
commit
ce541d1870
@ -358,29 +358,39 @@ class FormSemestre(db.Model):
|
||||
"""Test si sem est entièrement sur la même année scolaire.
|
||||
(ce n'est pas obligatoire mais si ce n'est pas le
|
||||
cas les exports Apogée risquent de mal fonctionner)
|
||||
Pivot au 1er août.
|
||||
Pivot au 1er août par défaut.
|
||||
"""
|
||||
if self.date_debut > self.date_fin:
|
||||
log(f"Warning: semestre {self.id} begins after ending !")
|
||||
annee_debut = self.date_debut.year
|
||||
if self.date_debut.month < 8: # août
|
||||
if self.date_debut.month <= scu.MONTH_FIN_ANNEE_SCOLAIRE: # juillet
|
||||
# considere que debut sur l'anne scolaire precedente
|
||||
annee_debut -= 1
|
||||
annee_fin = self.date_fin.year
|
||||
if self.date_fin.month < 9:
|
||||
if self.date_fin.month <= (scu.MONTH_FIN_ANNEE_SCOLAIRE + 1):
|
||||
# 9 (sept) pour autoriser un début en sept et une fin en aout
|
||||
annee_fin -= 1
|
||||
return annee_debut == annee_fin
|
||||
|
||||
def est_decale(self):
|
||||
"""Vrai si semestre "décalé"
|
||||
c'est à dire semestres impairs commençant entre janvier et juin
|
||||
et les pairs entre juillet et decembre
|
||||
c'est à dire semestres impairs commençant (par défaut)
|
||||
entre janvier et juin et les pairs entre juillet et décembre.
|
||||
"""
|
||||
if self.semestre_id <= 0:
|
||||
return False # formations sans semestres
|
||||
return (self.semestre_id % 2 and self.date_debut.month <= 6) or (
|
||||
not self.semestre_id % 2 and self.date_debut.month > 6
|
||||
return (
|
||||
# impair
|
||||
(
|
||||
self.semestre_id % 2
|
||||
and self.date_debut.month < scu.MONTH_FIN_ANNEE_SCOLAIRE
|
||||
)
|
||||
or
|
||||
# pair
|
||||
(
|
||||
(not self.semestre_id % 2)
|
||||
and self.date_debut.month >= scu.MONTH_FIN_ANNEE_SCOLAIRE
|
||||
)
|
||||
)
|
||||
|
||||
def etapes_apo_vdi(self) -> list[ApoEtapeVDI]:
|
||||
@ -936,8 +946,8 @@ class NotesSemSet(db.Model):
|
||||
|
||||
title = db.Column(db.Text)
|
||||
annee_scolaire = db.Column(db.Integer, nullable=True, default=None)
|
||||
# periode: 0 (année), 1 (Simpair), 2 (Spair)
|
||||
sem_id = db.Column(db.Integer, nullable=True, default=None)
|
||||
sem_id = db.Column(db.Integer, nullable=False, default=0)
|
||||
"période: 0 (année), 1 (Simpair), 2 (Spair)"
|
||||
|
||||
|
||||
# Association: many to many
|
||||
|
@ -31,20 +31,21 @@
|
||||
## fonctionalités
|
||||
|
||||
Le menu 'synchronisation avec Apogée' ne permet pas de traiter facilement les cas
|
||||
où un même code étape est implementé dans des semestres (au sens ScoDoc) différents.
|
||||
où un même code étape est implementé dans des formsemestres différents.
|
||||
|
||||
La proposition est d'ajouter à la page de description des ensembles de semestres
|
||||
On ajoute à la page de description des ensembles de semestres
|
||||
une section permettant de faire le point sur les cas particuliers.
|
||||
|
||||
Cette section est composée de deux parties:
|
||||
* Une partie effectif où figurent le nombre d'étudiants selon un répartition par
|
||||
|
||||
* Une partie effectif où figurent le nombre d'étudiants selon une répartition par
|
||||
semestre (en ligne) et par code étape (en colonne). On ajoute également des
|
||||
colonnes/lignes correspondant à des anomalies (étudiant sans code étape, sans
|
||||
semestre, avec deux semestres, sans NIP, etc.).
|
||||
|
||||
* La seconde partie présente la liste des étudiants. Il est possible qu'un
|
||||
* Une seconde partie présente la liste des étudiants. Il est possible qu'un
|
||||
même nom figure deux fois dans la liste (si on a pas pu faire la correspondance
|
||||
entre une inscription apogée et un étudiant d'un semestre, par exemple).
|
||||
entre une inscription Apogée et un étudiant d'un semestre, par exemple).
|
||||
|
||||
L'activation d'un des nombres du tableau 'effectifs' restreint l'affichage de
|
||||
la liste aux étudiants qui contribuent à ce nombre.
|
||||
@ -67,27 +68,25 @@ Cette classe compile la totalité des données:
|
||||
|
||||
Cette classe explore la suite semestres du semset.
|
||||
Pour chaque semestre, elle recense les étudiants du semestre et
|
||||
les codes étapes concernés.
|
||||
les codes étapes concernés, puis tous les codes étapes (toujours
|
||||
en important les étudiants de l'étape via le portail).
|
||||
|
||||
puis tous les codes étapes (toujours en important les étudiants de l'étape
|
||||
via le portail)
|
||||
|
||||
enfin on dispatch chaque étudiant dans une case - soit ordinaire, soit
|
||||
Enfin on dispatch chaque étudiant dans une case - soit ordinaire, soit
|
||||
correspondant à une anomalie.
|
||||
|
||||
### Modification de sco_etape_apogee_view.py
|
||||
|
||||
Pour insertion de l'affichage ajouté
|
||||
Pour insertion de l'affichage ajouté.
|
||||
|
||||
### Modification de sco_semset.py
|
||||
|
||||
Affichage proprement dit
|
||||
Affichage proprement dit.
|
||||
|
||||
### Modification de scp_formsemestre.py
|
||||
### Modification de sco_formsemestre.py
|
||||
|
||||
Modification/ajout de la méthode sem_in_semestre_scolaire pour permettre
|
||||
l'inscrition de semestres décalés (S1 en septembre, ...).
|
||||
Le filtrage s'effctue sur la date et non plus sur la parité du semestre (1-3/2-4).
|
||||
l'inscription de semestres décalés (S1 en septembre, ...).
|
||||
Le filtrage s'effectue sur la date et non plus sur la parité du semestre (1-3/2-4).
|
||||
"""
|
||||
|
||||
import json
|
||||
|
@ -28,6 +28,7 @@
|
||||
"""Operations de base sur les formsemestres
|
||||
"""
|
||||
from operator import itemgetter
|
||||
import datetime
|
||||
import time
|
||||
|
||||
from flask import g, request
|
||||
@ -421,6 +422,22 @@ def sem_set_responsable_name(sem):
|
||||
)
|
||||
|
||||
|
||||
def debut_in_semestre_scolaire(
|
||||
date_debut: datetime.date, year: int = False, saison: int = 0
|
||||
) -> bool:
|
||||
"""Vrai si date_debut est dans l'année scolaire ou le semestre
|
||||
indiquée par year et periode
|
||||
(par défaut, l'année scolaire en cours).
|
||||
periode:
|
||||
1 = sept,
|
||||
0 = janvier
|
||||
None = année complète
|
||||
"""
|
||||
if not year:
|
||||
year = scu.AnneeScolaire()
|
||||
# XXX WIP à voir selon ce que fait réellement sem_in_semestre_scolaire
|
||||
|
||||
|
||||
def sem_in_semestre_scolaire(sem, year=False, saison=0):
|
||||
"""n'utilise que la date de debut, pivot au 1er aout
|
||||
si annee non specifiée, année scolaire courante
|
||||
@ -436,13 +453,13 @@ def sem_in_semestre_scolaire(sem, year=False, saison=0):
|
||||
if not year:
|
||||
year = scu.AnneeScolaire()
|
||||
# est-on dans la même année universitaire ?
|
||||
if sem["mois_debut_ord"] > 7:
|
||||
if sem["mois_debut_ord"] > 7: # XXX
|
||||
if sem["annee_debut"] != str(year):
|
||||
return False
|
||||
else:
|
||||
if sem["annee_debut"] != str(year + 1):
|
||||
return False
|
||||
# rafinement éventuel sur le semestre
|
||||
# raffinement éventuel sur le semestre
|
||||
# saison is None => pas de rafinement => True
|
||||
if saison == 0:
|
||||
return True
|
||||
@ -454,36 +471,20 @@ def sem_in_semestre_scolaire(sem, year=False, saison=0):
|
||||
|
||||
def sem_in_annee_scolaire(sem, year=False):
|
||||
"""Test si sem appartient à l'année scolaire year (int).
|
||||
N'utilise que la date de debut, pivot au 1er août.
|
||||
Si annee non specifiée, année scolaire courante
|
||||
N'utilise que la date de début, pivot au 1er août.
|
||||
Si année non specifiée, année scolaire courante
|
||||
"""
|
||||
if not year:
|
||||
year = scu.AnneeScolaire()
|
||||
return ((sem["annee_debut"] == str(year)) and (sem["mois_debut_ord"] > 7)) or (
|
||||
(sem["annee_debut"] == str(year + 1)) and (sem["mois_debut_ord"] <= 7)
|
||||
return (
|
||||
(sem["annee_debut"] == str(year))
|
||||
and (sem["mois_debut_ord"] > scu.MONTH_FIN_ANNEE_SCOLAIRE)
|
||||
) or (
|
||||
(sem["annee_debut"] == str(year + 1))
|
||||
and (sem["mois_debut_ord"] <= scu.MONTH_FIN_ANNEE_SCOLAIRE)
|
||||
)
|
||||
|
||||
|
||||
def sem_une_annee(sem): # XXX deprecated: use FormSemestre.est_sur_une_annee()
|
||||
"""Test si sem est entièrement sur la même année scolaire.
|
||||
(ce n'est pas obligatoire mais si ce n'est pas le cas les exports Apogée ne vont pas fonctionner)
|
||||
pivot au 1er août.
|
||||
"""
|
||||
if sem["date_debut_iso"] > sem["date_fin_iso"]:
|
||||
log("Warning: semestre %(formsemestre_id)s begins after ending !" % sem)
|
||||
return False
|
||||
|
||||
debut = int(sem["annee_debut"])
|
||||
if sem["mois_debut_ord"] < 8: # considere que debut sur l'anne scolaire precedente
|
||||
debut -= 1
|
||||
fin = int(sem["annee_fin"])
|
||||
if (
|
||||
sem["mois_fin_ord"] < 9
|
||||
): # 9 (sept) pour autoriser un début en sept et une fin en aout
|
||||
fin -= 1
|
||||
return debut == fin
|
||||
|
||||
|
||||
def sem_est_courant(sem): # -> FormSemestre.est_courant
|
||||
"""Vrai si la date actuelle (now) est dans le semestre (les dates de début et fin sont incluses)"""
|
||||
now = time.strftime("%Y-%m-%d")
|
||||
|
@ -37,7 +37,7 @@ from app import db
|
||||
from app.auth.models import User
|
||||
from app.comp import res_sem
|
||||
from app.comp.res_compat import NotesTableCompat
|
||||
from app.models import ModuleImpl
|
||||
from app.models import FormSemestre, ModuleImpl
|
||||
from app.models.evaluations import Evaluation
|
||||
from app.models.ues import UniteEns
|
||||
import app.scodoc.sco_utils as scu
|
||||
@ -198,6 +198,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
||||
modimpl: ModuleImpl = ModuleImpl.query.get_or_404(moduleimpl_id)
|
||||
M = modimpl.to_dict()
|
||||
formsemestre_id = modimpl.formsemestre_id
|
||||
formsemestre: FormSemestre = modimpl.formsemestre
|
||||
Mod = sco_edit_module.module_list(args={"module_id": modimpl.module_id})[0]
|
||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
||||
@ -205,7 +206,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
||||
moduleimpl_id=M["moduleimpl_id"]
|
||||
)
|
||||
|
||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(modimpl.formsemestre)
|
||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||
|
||||
mod_evals = sco_evaluation_db.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
||||
mod_evals.sort(
|
||||
@ -333,9 +334,10 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
||||
)
|
||||
# Adapté à partir d'une suggestion de DS (Le Havre)
|
||||
# Liens saisies absences seulement si permission et date courante dans le semestre
|
||||
if current_user.has_permission(
|
||||
Permission.ScoAbsChange
|
||||
) and sco_formsemestre.sem_est_courant(sem):
|
||||
if (
|
||||
current_user.has_permission(Permission.ScoAbsChange)
|
||||
and formsemestre.est_courant()
|
||||
):
|
||||
datelundi = sco_abs.ddmmyyyy(time.strftime("%d/%m/%Y")).prev_monday()
|
||||
group_id = sco_groups.get_default_group(formsemestre_id)
|
||||
H.append(
|
||||
|
@ -104,9 +104,9 @@ class SemSet(dict):
|
||||
cnx,
|
||||
{"title": title, "annee_scolaire": annee_scolaire, "sem_id": sem_id},
|
||||
)
|
||||
log("created new semset_id=%s" % self.semset_id)
|
||||
log(f"created new semset_id={self.semset_id}")
|
||||
self.load_sems()
|
||||
# analyse des semestres pour construire le bilan par semestre et par étape
|
||||
# Analyse des semestres pour construire le bilan par semestre et par étape
|
||||
self.bilan = EtapeBilan()
|
||||
for sem in self.sems:
|
||||
self.bilan.add_sem(sem)
|
||||
@ -148,6 +148,7 @@ class SemSet(dict):
|
||||
sem["etapes_apo_str"] = sco_formsemestre.etapes_apo_str(sorted(list(ets)))
|
||||
|
||||
def add(self, formsemestre_id):
|
||||
"Ajoute ce semestre à l'ensemble"
|
||||
# check
|
||||
if formsemestre_id in self.formsemestre_ids:
|
||||
return # already there
|
||||
@ -155,8 +156,7 @@ class SemSet(dict):
|
||||
sem["formsemestre_id"] for sem in self.list_possible_sems()
|
||||
]:
|
||||
raise ValueError(
|
||||
"can't add %s to set %s: incompatible sem_id"
|
||||
% (formsemestre_id, self.semset_id)
|
||||
f"can't add {formsemestre_id} to set {self.semset_id}: incompatible sem_id"
|
||||
)
|
||||
|
||||
ndb.SimpleQuery(
|
||||
|
@ -160,6 +160,10 @@ EVALUATION_NORMALE = 0
|
||||
EVALUATION_RATTRAPAGE = 1
|
||||
EVALUATION_SESSION2 = 2
|
||||
|
||||
# Dates et années scolaires
|
||||
MONTH_FIN_ANNEE_SCOLAIRE = 7 # juillet (TODO: passer en paramètre config.)
|
||||
DAY_FIN_ANNEE_SCOLAIRE = 31 # TODO calculer en fct du mois
|
||||
|
||||
MONTH_NAMES_ABBREV = (
|
||||
"Jan ",
|
||||
"Fév ",
|
||||
@ -461,18 +465,6 @@ def NotesURL():
|
||||
return url_for("notes.index_html", scodoc_dept=g.scodoc_dept)[: -len("/index_html")]
|
||||
|
||||
|
||||
def EntreprisesURL():
|
||||
"""URL of Enterprises
|
||||
e.g. https://scodoc.xxx.fr/ScoDoc/DEPT/Scolarite/Entreprises
|
||||
= url de base des requêtes de ZEntreprises
|
||||
et page accueil Entreprises
|
||||
"""
|
||||
return "NotImplemented"
|
||||
# url_for("entreprises.index_html", scodoc_dept=g.scodoc_dept)[
|
||||
# : -len("/index_html")
|
||||
# ]
|
||||
|
||||
|
||||
def AbsencesURL():
|
||||
"""URL of Absences"""
|
||||
return url_for("absences.index_html", scodoc_dept=g.scodoc_dept)[
|
||||
@ -918,7 +910,7 @@ def annee_scolaire_repr(year, month):
|
||||
"""representation de l'annee scolaire : '2009 - 2010'
|
||||
à partir d'une date.
|
||||
"""
|
||||
if month > 7: # apres le 1er aout
|
||||
if month > MONTH_FIN_ANNEE_SCOLAIRE: # apres le 1er aout
|
||||
return "%s - %s" % (year, year + 1)
|
||||
else:
|
||||
return "%s - %s" % (year - 1, year)
|
||||
@ -926,7 +918,7 @@ def annee_scolaire_repr(year, month):
|
||||
|
||||
def annee_scolaire_debut(year, month) -> int:
|
||||
"""Annee scolaire de debut (septembre): heuristique pour l'hémisphère nord..."""
|
||||
if int(month) > 7:
|
||||
if int(month) > MONTH_FIN_ANNEE_SCOLAIRE:
|
||||
return int(year)
|
||||
else:
|
||||
return int(year) - 1
|
||||
@ -943,7 +935,11 @@ def date_fin_anne_scolaire(annee_scolaire: int) -> datetime:
|
||||
"""La date de fin de l'année scolaire
|
||||
= 31 juillet de l'année suivante
|
||||
"""
|
||||
return datetime.datetime(year=annee_scolaire + 1, month=7, day=31)
|
||||
return datetime.datetime(
|
||||
year=annee_scolaire + 1,
|
||||
month=MONTH_FIN_ANNEE_SCOLAIRE,
|
||||
day=DAY_FIN_ANNEE_SCOLAIRE,
|
||||
)
|
||||
|
||||
|
||||
def sem_decale_str(sem):
|
||||
|
36
migrations/versions/5542cac8c34a_semset_periode.py
Normal file
36
migrations/versions/5542cac8c34a_semset_periode.py
Normal file
@ -0,0 +1,36 @@
|
||||
"""semset_periode
|
||||
|
||||
Revision ID: 5542cac8c34a
|
||||
Revises: 52f5f35c077f
|
||||
Create Date: 2022-11-08 01:17:51.983042
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.orm import sessionmaker # added by ev
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "5542cac8c34a"
|
||||
down_revision = "52f5f35c077f"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
Session = sessionmaker()
|
||||
|
||||
|
||||
def upgrade():
|
||||
#
|
||||
bind = op.get_bind()
|
||||
session = Session(bind=bind)
|
||||
session.execute("""UPDATE notes_semset SET sem_id=0 WHERE sem_id IS NULL;""")
|
||||
op.alter_column(
|
||||
"notes_semset", "sem_id", existing_type=sa.INTEGER(), nullable=False
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column("notes_semset", "sem_id", existing_type=sa.INTEGER(), nullable=True)
|
||||
# ### end Alembic commands ###
|
@ -7,7 +7,6 @@ Create Date: 2022-02-15 21:47:29.212329
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
from sqlalchemy.orm import sessionmaker # added by ev
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
Loading…
Reference in New Issue
Block a user