forked from ScoDoc/ScoDoc
Assiduité : WIP saisie excel
This commit is contained in:
parent
e6a165b18a
commit
abb460e659
@ -78,8 +78,9 @@ from app.scodoc.sco_permissions import Permission
|
|||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc import sco_groups_view
|
from app.scodoc import sco_groups_view, sco_groups
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
|
from app.scodoc import sco_excel
|
||||||
from app.scodoc import sco_find_etud
|
from app.scodoc import sco_find_etud
|
||||||
from app.scodoc import sco_assiduites as scass
|
from app.scodoc import sco_assiduites as scass
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
@ -2218,9 +2219,291 @@ def generate_bul_list(etud: Identite, semestre: FormSemestre) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("feuille_abs_hebdo", methods=["GET", "POST"])
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.AbsChange)
|
||||||
|
def feuille_abs_hebdo():
|
||||||
|
"""
|
||||||
|
GET : Renvoie un tableau excel pour permettre la saisie des absences
|
||||||
|
POST: Enregistre les absences saisies
|
||||||
|
Affiche un choix de semaine si "week" n'est pas renseigné
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Récupération des groupes
|
||||||
|
group_ids: str = request.args.get("group_ids", "")
|
||||||
|
if group_ids == "":
|
||||||
|
raise ScoValueError("Paramètre 'group_ids' manquant", dest_url=request.referrer)
|
||||||
|
|
||||||
|
# Vérification du semestre
|
||||||
|
formsemestre_id: int = request.args.get("formsemestre_id", -1)
|
||||||
|
formsemestre: FormSemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
|
|
||||||
|
# Vériication de la semaine
|
||||||
|
week: str = request.args.get("week", datetime.datetime.now().strftime("%G-W%V"))
|
||||||
|
|
||||||
|
regex_iso8601 = r"^\d{4}-W\d{2}$"
|
||||||
|
if week and not re.match(regex_iso8601, week):
|
||||||
|
raise ScoValueError("Semaine invalide", dest_url=request.referrer)
|
||||||
|
|
||||||
|
fs_deb_iso8601 = formsemestre.date_debut.strftime("%Y-W%W")
|
||||||
|
fs_fin_iso8601 = formsemestre.date_fin.strftime("%Y-W%W")
|
||||||
|
|
||||||
|
# Utilisation de la propriété de la norme iso 8601
|
||||||
|
# les chaines sont triables par ordre alphanumérique croissant
|
||||||
|
# et produiront le même ordre que les dates par ordre chronologique croissant
|
||||||
|
if (not week) or week < fs_deb_iso8601 or week > fs_fin_iso8601:
|
||||||
|
if week:
|
||||||
|
flash(
|
||||||
|
"""La semaine n'est pas dans le semestre,
|
||||||
|
choisissez la semaine sur laquelle saisir l'assiduité"""
|
||||||
|
)
|
||||||
|
return sco_gen_cal.calendrier_choix_date(
|
||||||
|
date_debut=formsemestre.date_debut,
|
||||||
|
date_fin=formsemestre.date_fin,
|
||||||
|
url=url_for(
|
||||||
|
"assiduites.feuilles_abs_hebdo",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
formsemestre_id=formsemestre_id,
|
||||||
|
group_ids=group_ids,
|
||||||
|
week="placeholder",
|
||||||
|
),
|
||||||
|
mode="semaine",
|
||||||
|
titre="Choix de la semaine",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Vérification des groupes
|
||||||
|
group_ids = group_ids.split(",") if group_ids != "" else []
|
||||||
|
|
||||||
|
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||||
|
group_ids, formsemestre_id=formsemestre.id, select_all_when_unspecified=True
|
||||||
|
)
|
||||||
|
if not groups_infos.members:
|
||||||
|
return (
|
||||||
|
html_sco_header.sco_header(
|
||||||
|
page_title="Assiduité: feuille saisie hebdomadaire"
|
||||||
|
)
|
||||||
|
+ "<h3>Aucun étudiant ! </h3>"
|
||||||
|
+ html_sco_header.sco_footer()
|
||||||
|
)
|
||||||
|
|
||||||
|
# Gestion des jours
|
||||||
|
jours: dict[str, list[str]] = {
|
||||||
|
"lun": [
|
||||||
|
"Lundi",
|
||||||
|
datetime.datetime.strptime(week + "-1", "%G-W%V-%u").strftime("%d/%m/%Y"),
|
||||||
|
],
|
||||||
|
"mar": [
|
||||||
|
"Mardi",
|
||||||
|
datetime.datetime.strptime(week + "-2", "%G-W%V-%u").strftime("%d/%m/%Y"),
|
||||||
|
],
|
||||||
|
"mer": [
|
||||||
|
"Mercredi",
|
||||||
|
datetime.datetime.strptime(week + "-3", "%G-W%V-%u").strftime("%d/%m/%Y"),
|
||||||
|
],
|
||||||
|
"jeu": [
|
||||||
|
"Jeudi",
|
||||||
|
datetime.datetime.strptime(week + "-4", "%G-W%V-%u").strftime("%d/%m/%Y"),
|
||||||
|
],
|
||||||
|
"ven": [
|
||||||
|
"Vendredi",
|
||||||
|
datetime.datetime.strptime(week + "-5", "%G-W%V-%u").strftime("%d/%m/%Y"),
|
||||||
|
],
|
||||||
|
"sam": [
|
||||||
|
"Samedi",
|
||||||
|
datetime.datetime.strptime(week + "-6", "%G-W%V-%u").strftime("%d/%m/%Y"),
|
||||||
|
],
|
||||||
|
"dim": [
|
||||||
|
"Dimanche",
|
||||||
|
datetime.datetime.strptime(week + "-7", "%G-W%V-%u").strftime("%d/%m/%Y"),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
non_travail = sco_preferences.get_preference("non_travail")
|
||||||
|
non_travail = non_travail.replace(" ", "").split(",")
|
||||||
|
|
||||||
|
hebdo_jours: list[tuple[bool, str]] = []
|
||||||
|
for key, val in jours.items():
|
||||||
|
hebdo_jours.append((key in non_travail, val))
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
flash("Les absences ont bien été enregistrées")
|
||||||
|
return redirect(request.referrer)
|
||||||
|
|
||||||
|
filename = f"feuille_signal_abs_{week}"
|
||||||
|
xls = _excel_feuille_abs(
|
||||||
|
formsemestre=formsemestre, groups_infos=groups_infos, hebdo_jours=hebdo_jours
|
||||||
|
)
|
||||||
|
return scu.send_file(xls, filename, scu.XLSX_SUFFIX, mime=scu.XLSX_MIMETYPE)
|
||||||
|
|
||||||
|
|
||||||
# --- Fonctions internes ---
|
# --- Fonctions internes ---
|
||||||
|
|
||||||
|
|
||||||
|
def _excel_feuille_abs(
|
||||||
|
formsemestre: FormSemestre,
|
||||||
|
groups_infos: sco_groups_view.DisplayedGroupsInfos,
|
||||||
|
hebdo_jours: list[tuple[bool, str]],
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Génère un fichier excel pour la saisie des absences hebdomadaires
|
||||||
|
|
||||||
|
Colonnes :
|
||||||
|
- A : [formsemestre_id][etudid...]
|
||||||
|
- B : [nom][nom...]
|
||||||
|
- C : [prenom][prenom...]
|
||||||
|
- D : [groupes][groupe...]
|
||||||
|
- 2 colonnes (matin/aprem) par jour de la semaine
|
||||||
|
"""
|
||||||
|
|
||||||
|
ws = sco_excel.ScoExcelSheet("Saisie_ABS")
|
||||||
|
|
||||||
|
# == Préparation des données ==
|
||||||
|
lines: list[tuple] = []
|
||||||
|
|
||||||
|
for membre in groups_infos.members:
|
||||||
|
etudid = membre["etudid"]
|
||||||
|
groups = sco_groups.get_etud_groups(etudid, formsemestre_id=formsemestre.id)
|
||||||
|
grc = sco_groups.listgroups_abbrev(groups)
|
||||||
|
line = [
|
||||||
|
str(etudid),
|
||||||
|
membre["nom"].upper(),
|
||||||
|
membre["prenom"].lower().capitalize(),
|
||||||
|
membre["etat"],
|
||||||
|
grc,
|
||||||
|
]
|
||||||
|
line += ["" for _ in range(len(hebdo_jours) * 2)]
|
||||||
|
lines.append(line)
|
||||||
|
|
||||||
|
# == Préparation du fichier ==
|
||||||
|
|
||||||
|
# colonnes
|
||||||
|
lettres: str = "EFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
# ajuste largeurs colonnes (unite inconnue, empirique)
|
||||||
|
ws.set_column_dimension_width("A", 11.0 / 7) # codes
|
||||||
|
# ws.set_column_dimension_hidden("A", True) # codes
|
||||||
|
ws.set_column_dimension_width("B", 164.00 / 7) # noms
|
||||||
|
ws.set_column_dimension_width("C", 109.0 / 7) # prenoms
|
||||||
|
ws.set_column_dimension_width("D", 164.0 / 7) # groupes
|
||||||
|
|
||||||
|
i: int = 0
|
||||||
|
for jour in hebdo_jours:
|
||||||
|
ws.set_column_dimension_width(lettres[i], 100.0 / 7)
|
||||||
|
ws.set_column_dimension_width(lettres[i + 1], 100.0 / 7)
|
||||||
|
if jour[0]:
|
||||||
|
ws.set_column_dimension_hidden(lettres[i], True)
|
||||||
|
ws.set_column_dimension_hidden(lettres[i + 1], True)
|
||||||
|
i += 2
|
||||||
|
|
||||||
|
# fontes
|
||||||
|
font_base = sco_excel.Font(name="Arial", size=12)
|
||||||
|
font_bold = sco_excel.Font(name="Arial", bold=True)
|
||||||
|
font_italic = sco_excel.Font(
|
||||||
|
name="Arial", size=12, italic=True, color=sco_excel.COLORS.RED.value
|
||||||
|
)
|
||||||
|
font_titre = sco_excel.Font(name="Arial", bold=True, size=14)
|
||||||
|
font_purple = sco_excel.Font(name="Arial", color=sco_excel.COLORS.PURPLE.value)
|
||||||
|
font_brown = sco_excel.Font(name="Arial", color=sco_excel.COLORS.BROWN.value)
|
||||||
|
|
||||||
|
# bordures
|
||||||
|
side_thin = sco_excel.Side(border_style="thin", color=sco_excel.COLORS.BLACK.value)
|
||||||
|
border_top = sco_excel.Border(top=side_thin)
|
||||||
|
border_right = sco_excel.Border(right=side_thin)
|
||||||
|
border_sides = sco_excel.Border(left=side_thin, right=side_thin, bottom=side_thin)
|
||||||
|
|
||||||
|
# fonds
|
||||||
|
fill_light_yellow = sco_excel.PatternFill(
|
||||||
|
patternType="solid", fgColor=sco_excel.COLORS.LIGHT_YELLOW.value
|
||||||
|
)
|
||||||
|
|
||||||
|
# styles
|
||||||
|
style_titres = {"font": font_titre}
|
||||||
|
style_expl = {"font": font_italic}
|
||||||
|
|
||||||
|
style_ro = { # cells read-only
|
||||||
|
"font": font_purple,
|
||||||
|
"border": border_right,
|
||||||
|
}
|
||||||
|
style_dem = {
|
||||||
|
"font": font_brown,
|
||||||
|
"border": border_top,
|
||||||
|
}
|
||||||
|
style_nom = { # style pour nom, prenom, groupe
|
||||||
|
"font": font_base,
|
||||||
|
"border": border_top,
|
||||||
|
}
|
||||||
|
style_abs = {
|
||||||
|
"font": font_bold,
|
||||||
|
"fill": fill_light_yellow,
|
||||||
|
"border": border_sides,
|
||||||
|
}
|
||||||
|
|
||||||
|
# filtre
|
||||||
|
filter_top = 6
|
||||||
|
filter_bottom = filter_top + len(lines)
|
||||||
|
filter_left = "A"
|
||||||
|
filter_right = lettres[len(hebdo_jours) * 2 - 1]
|
||||||
|
ws.set_auto_filter(f"${filter_left}${filter_top}:${filter_right}${filter_bottom}")
|
||||||
|
|
||||||
|
# == Ecritures statiques ==
|
||||||
|
ws.append_single_cell_row(
|
||||||
|
"Saisir les assiduités dans les cases jaunes", style=style_expl
|
||||||
|
)
|
||||||
|
ws.append_single_cell_row("Ne pas modifier les cases en mauve !", style_expl)
|
||||||
|
# Nom du semestre
|
||||||
|
ws.append_single_cell_row(
|
||||||
|
scu.unescape_html(formsemestre.titre_annee()), style_titres
|
||||||
|
)
|
||||||
|
# ligne blanche
|
||||||
|
ws.append_blank_row()
|
||||||
|
|
||||||
|
# == Ecritures dynamiques ==
|
||||||
|
# Ecriture des entêtes
|
||||||
|
row = [ws.make_cell("", style=style_titres) for _ in range(4)]
|
||||||
|
for jour in hebdo_jours:
|
||||||
|
row.append(ws.make_cell(" ".join(jour[1]), style=style_titres))
|
||||||
|
row.append(ws.make_cell("", style=style_titres))
|
||||||
|
ws.append_row(row)
|
||||||
|
|
||||||
|
row = [
|
||||||
|
ws.make_cell(f"!{formsemestre.id}", style=style_ro),
|
||||||
|
ws.make_cell("Nom", style=style_titres),
|
||||||
|
ws.make_cell("Prénom", style=style_titres),
|
||||||
|
ws.make_cell("Groupe", style=style_titres),
|
||||||
|
]
|
||||||
|
|
||||||
|
for jour in hebdo_jours:
|
||||||
|
row.append(ws.make_cell("Matin", style=style_titres))
|
||||||
|
row.append(ws.make_cell("Après-Midi", style=style_titres))
|
||||||
|
|
||||||
|
ws.append_row(row)
|
||||||
|
|
||||||
|
# Ecriture des données
|
||||||
|
for line in lines:
|
||||||
|
st = style_nom
|
||||||
|
if line[3] != "I":
|
||||||
|
st = style_dem
|
||||||
|
if line[3] == "D": # demissionnaire
|
||||||
|
s = "DEM"
|
||||||
|
else:
|
||||||
|
s = line[3] # etat autre
|
||||||
|
else:
|
||||||
|
s = line[4] # groupes TD/TP/...
|
||||||
|
ws.append_row(
|
||||||
|
[
|
||||||
|
ws.make_cell("!" + line[0], style_ro), # code
|
||||||
|
ws.make_cell(line[1], st),
|
||||||
|
ws.make_cell(line[2], st),
|
||||||
|
ws.make_cell(s, st),
|
||||||
|
]
|
||||||
|
+ [ws.make_cell(" ", style_abs) for _ in range(len(hebdo_jours) * 2)]
|
||||||
|
)
|
||||||
|
|
||||||
|
# ligne blanche
|
||||||
|
ws.append_blank_row()
|
||||||
|
|
||||||
|
return ws.generate()
|
||||||
|
|
||||||
|
|
||||||
def _dateiso_to_datefr(date_iso: str) -> str:
|
def _dateiso_to_datefr(date_iso: str) -> str:
|
||||||
"""
|
"""
|
||||||
_dateiso_to_datefr Transforme une date iso en date format français
|
_dateiso_to_datefr Transforme une date iso en date format français
|
||||||
|
Loading…
Reference in New Issue
Block a user