forked from ScoDoc/ScoDoc
Compare commits
10 Commits
0441e6cd64
...
4cb7479b6f
Author | SHA1 | Date | |
---|---|---|---|
4cb7479b6f | |||
95a2a3daeb | |||
b3ba3002ea | |||
e8be809dff | |||
4d513bf318 | |||
2b04c952c4 | |||
2280956b18 | |||
2944fb0795 | |||
5f49355ec3 | |||
892d1e9967 |
@ -569,10 +569,14 @@ def formsemestre_edt(formsemestre_id: int):
|
||||
Si ok, une liste d'évènements. Sinon, une chaine indiquant un message d'erreur.
|
||||
|
||||
group_ids permet de filtrer sur les groupes ScoDoc.
|
||||
show_modules_titles affiche le titre complet du module (défaut), sinon juste le code.
|
||||
"""
|
||||
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
||||
if g.scodoc_dept:
|
||||
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
||||
formsemestre: FormSemestre = query.first_or_404(formsemestre_id)
|
||||
group_ids = request.args.getlist("group_ids", int)
|
||||
return sco_edt_cal.formsemestre_edt_dict(formsemestre, group_ids=group_ids)
|
||||
show_modules_titles = scu.to_bool(request.args.get("show_modules_titles", False))
|
||||
return sco_edt_cal.formsemestre_edt_dict(
|
||||
formsemestre, group_ids=group_ids, show_modules_titles=show_modules_titles
|
||||
)
|
||||
|
@ -11,6 +11,7 @@ from flask_json import as_json
|
||||
from flask import g, request
|
||||
from flask_login import login_required, current_user
|
||||
from flask_sqlalchemy.query import Query
|
||||
from werkzeug.exceptions import NotFound
|
||||
|
||||
import app.scodoc.sco_assiduites as scass
|
||||
import app.scodoc.sco_utils as scu
|
||||
@ -150,7 +151,7 @@ def justificatifs(etudid: int = None, nip=None, ine=None, with_query: bool = Fal
|
||||
@as_json
|
||||
@permission_required(Permission.ScoView)
|
||||
def justificatifs_dept(dept_id: int = None, with_query: bool = False):
|
||||
""" """
|
||||
"""XXX TODO missing doc"""
|
||||
|
||||
# Récupération du département et des étudiants du département
|
||||
dept: Departement = Departement.query.get_or_404(dept_id)
|
||||
@ -373,7 +374,7 @@ def _create_one(
|
||||
date_debut=deb,
|
||||
date_fin=fin,
|
||||
etat=etat,
|
||||
etud=etud,
|
||||
etudiant=etud,
|
||||
raison=raison,
|
||||
user_id=current_user.id,
|
||||
external_data=external_data,
|
||||
@ -419,9 +420,7 @@ def justif_edit(justif_id: int):
|
||||
"""
|
||||
|
||||
# Récupération du justificatif à modifier
|
||||
justificatif_unique: Query = Justificatif.query.filter_by(
|
||||
id=justif_id
|
||||
).first_or_404()
|
||||
justificatif_unique = Justificatif.get_justificatif(justif_id)
|
||||
|
||||
errors: list[str] = []
|
||||
data = request.get_json(force=True)
|
||||
@ -497,7 +496,7 @@ def justif_edit(justif_id: int):
|
||||
retour = {
|
||||
"couverture": {
|
||||
"avant": avant_ids,
|
||||
"après": compute_assiduites_justified(
|
||||
"apres": compute_assiduites_justified(
|
||||
justificatif_unique.etudid,
|
||||
[justificatif_unique],
|
||||
True,
|
||||
@ -561,12 +560,10 @@ def _delete_one(justif_id: int) -> tuple[int, str]:
|
||||
message : OK si réussi, message d'erreur sinon
|
||||
"""
|
||||
# Récupération du justificatif à supprimer
|
||||
justificatif_unique: Justificatif = Justificatif.query.filter_by(
|
||||
id=justif_id
|
||||
).first()
|
||||
if justificatif_unique is None:
|
||||
try:
|
||||
justificatif_unique = Justificatif.get_justificatif(justif_id)
|
||||
except NotFound:
|
||||
return (404, "Justificatif non existant")
|
||||
|
||||
# Récupération de l'archive du justificatif
|
||||
archive_name: str = justificatif_unique.fichier
|
||||
|
||||
@ -612,10 +609,7 @@ def justif_import(justif_id: int = None):
|
||||
return json_error(404, "Il n'y a pas de fichier joint")
|
||||
|
||||
# On récupère le justificatif auquel on va importer le fichier
|
||||
query: Query = Justificatif.query.filter_by(id=justif_id)
|
||||
if g.scodoc_dept:
|
||||
query = query.join(Identite).filter_by(dept_id=g.scodoc_dept_id)
|
||||
justificatif_unique: Justificatif = query.first_or_404()
|
||||
justificatif_unique = Justificatif.get_justificatif(justif_id)
|
||||
|
||||
# Récupération de l'archive si elle existe
|
||||
archive_name: str = justificatif_unique.fichier
|
||||
@ -658,10 +652,7 @@ def justif_export(justif_id: int | None = None, filename: str | None = None):
|
||||
La permission est ScoView + (AbsJustifView ou être l'auteur du justifcatif)
|
||||
"""
|
||||
# On récupère le justificatif concerné
|
||||
query: Query = Justificatif.query.filter_by(id=justif_id)
|
||||
if g.scodoc_dept:
|
||||
query = query.join(Identite).filter_by(dept_id=g.scodoc_dept_id)
|
||||
justificatif_unique: Justificatif = query.first_or_404()
|
||||
justificatif_unique = Justificatif.get_justificatif(justif_id)
|
||||
|
||||
# Vérification des permissions
|
||||
if not (
|
||||
@ -694,6 +685,7 @@ def justif_export(justif_id: int | None = None, filename: str | None = None):
|
||||
@as_json
|
||||
@permission_required(Permission.AbsChange)
|
||||
def justif_remove(justif_id: int = None):
|
||||
# XXX TODO pas de test unitaire
|
||||
"""
|
||||
Supression d'un fichier ou d'une archive
|
||||
{
|
||||
@ -710,10 +702,7 @@ def justif_remove(justif_id: int = None):
|
||||
data: dict = request.get_json(force=True)
|
||||
|
||||
# On récupère le justificatif concerné
|
||||
query: Query = Justificatif.query.filter_by(id=justif_id)
|
||||
if g.scodoc_dept:
|
||||
query = query.join(Identite).filter_by(dept_id=g.scodoc_dept_id)
|
||||
justificatif_unique: Justificatif = query.first_or_404()
|
||||
justificatif_unique = Justificatif.get_justificatif(justif_id)
|
||||
|
||||
# On récupère l'archive
|
||||
archive_name: str = justificatif_unique.fichier
|
||||
@ -775,10 +764,7 @@ def justif_list(justif_id: int = None):
|
||||
"""
|
||||
|
||||
# Récupération du justificatif concerné
|
||||
query: Query = Justificatif.query.filter_by(id=justif_id)
|
||||
if g.scodoc_dept:
|
||||
query = query.join(Identite).filter_by(dept_id=g.scodoc_dept_id)
|
||||
justificatif_unique: Justificatif = query.first_or_404()
|
||||
justificatif_unique = Justificatif.get_justificatif(justif_id)
|
||||
|
||||
# Récupération de l'archive avec l'archiver
|
||||
archive_name: str = justificatif_unique.fichier
|
||||
@ -820,10 +806,7 @@ def justif_justifies(justif_id: int = None):
|
||||
"""
|
||||
|
||||
# On récupère le justificatif concerné
|
||||
query: Query = Justificatif.query.filter_by(id=justif_id)
|
||||
if g.scodoc_dept:
|
||||
query = query.join(Identite).filter_by(dept_id=g.scodoc_dept_id)
|
||||
justificatif_unique: Justificatif = query.first_or_404()
|
||||
justificatif_unique = Justificatif.get_justificatif(justif_id)
|
||||
|
||||
# On récupère la liste des assiduités justifiées par le justificatif
|
||||
assiduites_list: list[int] = scass.justifies(justificatif_unique)
|
||||
@ -837,6 +820,7 @@ def justif_justifies(justif_id: int = None):
|
||||
def _filter_manager(requested, justificatifs_query: Query):
|
||||
"""
|
||||
Retourne les justificatifs entrés filtrés en fonction de la request
|
||||
et du département courant s'il y en a un
|
||||
"""
|
||||
# cas 1 : etat justificatif
|
||||
etat: str = requested.args.get("etat")
|
||||
@ -871,7 +855,7 @@ def _filter_manager(requested, justificatifs_query: Query):
|
||||
formsemestre: FormSemestre = None
|
||||
try:
|
||||
formsemestre_id = int(formsemestre_id)
|
||||
formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first()
|
||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||
justificatifs_query = scass.filter_by_formsemestre(
|
||||
justificatifs_query, Justificatif, formsemestre
|
||||
)
|
||||
@ -906,4 +890,10 @@ def _filter_manager(requested, justificatifs_query: Query):
|
||||
except ValueError:
|
||||
group_id = None
|
||||
|
||||
# Département
|
||||
if g.scodoc_dept:
|
||||
justificatifs_query = justificatifs_query.join(Identite).filter_by(
|
||||
dept_id=g.scodoc_dept_id
|
||||
)
|
||||
|
||||
return justificatifs_query
|
||||
|
@ -40,6 +40,7 @@ from wtforms import (
|
||||
validators,
|
||||
)
|
||||
from wtforms.validators import DataRequired
|
||||
from app.scodoc import sco_utils as scu
|
||||
|
||||
|
||||
class AjoutAssiOrJustForm(FlaskForm):
|
||||
@ -98,15 +99,7 @@ class AjoutAssiOrJustForm(FlaskForm):
|
||||
"id": "assi_date_fin",
|
||||
},
|
||||
)
|
||||
assi_raison = TextAreaField(
|
||||
"Raison",
|
||||
render_kw={
|
||||
"id": "assi_raison",
|
||||
"cols": 75,
|
||||
"rows": 4,
|
||||
"maxlength": 500,
|
||||
},
|
||||
)
|
||||
|
||||
entry_date = StringField(
|
||||
"Date de dépot ou saisie",
|
||||
validators=[validators.Length(max=10)],
|
||||
@ -122,7 +115,15 @@ class AjoutAssiOrJustForm(FlaskForm):
|
||||
|
||||
class AjoutAssiduiteEtudForm(AjoutAssiOrJustForm):
|
||||
"Formulaire de saisie d'une assiduité pour un étudiant"
|
||||
|
||||
description = TextAreaField(
|
||||
"Description",
|
||||
render_kw={
|
||||
"id": "description",
|
||||
"cols": 75,
|
||||
"rows": 4,
|
||||
"maxlength": 500,
|
||||
},
|
||||
)
|
||||
assi_etat = RadioField(
|
||||
"Signaler:",
|
||||
choices=[("absent", "absence"), ("retard", "retard"), ("present", "présence")],
|
||||
@ -139,16 +140,24 @@ class AjoutAssiduiteEtudForm(AjoutAssiOrJustForm):
|
||||
|
||||
class AjoutJustificatifEtudForm(AjoutAssiOrJustForm):
|
||||
"Formulaire de saisie d'un justificatif pour un étudiant"
|
||||
|
||||
raison = TextAreaField(
|
||||
"Raison",
|
||||
render_kw={
|
||||
"id": "raison",
|
||||
"cols": 75,
|
||||
"rows": 4,
|
||||
"maxlength": 500,
|
||||
},
|
||||
)
|
||||
etat = SelectField(
|
||||
"État du justificatif",
|
||||
choices=[
|
||||
("", "Choisir..."), # Placeholder
|
||||
("attente", "En attente de validation"),
|
||||
("non_valide", "Non valide"),
|
||||
("modifie", "Modifié"),
|
||||
("valide", "Valide"),
|
||||
(scu.EtatJustificatif.ATTENTE.value, "En attente de validation"),
|
||||
(scu.EtatJustificatif.NON_VALIDE.value, "Non valide"),
|
||||
(scu.EtatJustificatif.MODIFIE.value, "Modifié"),
|
||||
(scu.EtatJustificatif.VALIDE.value, "Valide"),
|
||||
],
|
||||
validators=[DataRequired(message="This field is required.")],
|
||||
)
|
||||
fichiers = MultipleFileField()
|
||||
fichiers = MultipleFileField(label="Ajouter des fichiers")
|
||||
|
@ -503,6 +503,7 @@ class Justificatif(ScoDocModel):
|
||||
archiver: JustificatifArchiver = JustificatifArchiver()
|
||||
filenames = archiver.list_justificatifs(archive_name, self.etudiant)
|
||||
accessible_filenames = []
|
||||
#
|
||||
for filename in filenames:
|
||||
if int(filename[1]) == current_user.id or current_user.has_permission(
|
||||
Permission.AbsJustifView
|
||||
|
@ -49,7 +49,6 @@
|
||||
"""
|
||||
import datetime
|
||||
import glob
|
||||
import json
|
||||
import mimetypes
|
||||
import os
|
||||
import re
|
||||
@ -58,29 +57,17 @@ import time
|
||||
|
||||
import chardet
|
||||
|
||||
import flask
|
||||
from flask import flash, g, request, url_for
|
||||
from flask import g
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
from config import Config
|
||||
from app import log, ScoDocJSONEncoder
|
||||
from app.but import jury_but_pv
|
||||
from app.comp import res_sem
|
||||
from app.comp.res_compat import NotesTableCompat
|
||||
from app.models import FormSemestre
|
||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||
from app.scodoc.sco_exceptions import ScoException, ScoPermissionDenied
|
||||
from app.scodoc import html_sco_header
|
||||
from app.scodoc import sco_bulletins_pdf
|
||||
from app.scodoc import sco_groups
|
||||
from app.scodoc import sco_groups_view
|
||||
from app.scodoc import sco_pv_forms
|
||||
from app.scodoc import sco_pv_lettres_inviduelles
|
||||
from app.scodoc import sco_pv_pdf
|
||||
from app import log
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
class BaseArchiver:
|
||||
"""Classe de base pour tous les archivers"""
|
||||
|
||||
def __init__(self, archive_type=""):
|
||||
self.archive_type = archive_type
|
||||
self.initialized = False
|
||||
@ -306,400 +293,3 @@ class BaseArchiver:
|
||||
mime = "application/octet-stream"
|
||||
|
||||
return scu.send_file(data, filename, mime=mime)
|
||||
|
||||
|
||||
class SemsArchiver(BaseArchiver):
|
||||
def __init__(self):
|
||||
BaseArchiver.__init__(self, archive_type="")
|
||||
|
||||
|
||||
PV_ARCHIVER = SemsArchiver()
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def do_formsemestre_archive(
|
||||
formsemestre_id,
|
||||
group_ids: list[int] = None, # si indiqué, ne prend que ces groupes
|
||||
description="",
|
||||
date_jury="",
|
||||
signature=None, # pour lettres indiv
|
||||
date_commission=None,
|
||||
numero_arrete=None,
|
||||
code_vdi=None,
|
||||
show_title=False,
|
||||
pv_title=None,
|
||||
pv_title_session=None,
|
||||
with_paragraph_nom=False,
|
||||
anonymous=False,
|
||||
bul_version="long",
|
||||
):
|
||||
"""Make and store new archive for this formsemestre.
|
||||
Store:
|
||||
- tableau recap (xls), pv jury (xls et pdf), bulletins (xml et pdf), lettres individuelles (pdf)
|
||||
"""
|
||||
from app.scodoc.sco_recapcomplet import (
|
||||
gen_formsemestre_recapcomplet_excel,
|
||||
gen_formsemestre_recapcomplet_html_table,
|
||||
gen_formsemestre_recapcomplet_json,
|
||||
)
|
||||
|
||||
if bul_version not in scu.BULLETINS_VERSIONS:
|
||||
raise ScoValueError(
|
||||
"do_formsemestre_archive: version de bulletin demandée invalide"
|
||||
)
|
||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||
res: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||
sem_archive_id = formsemestre_id
|
||||
archive_id = PV_ARCHIVER.create_obj_archive(
|
||||
sem_archive_id, description, formsemestre.dept_id
|
||||
)
|
||||
date = PV_ARCHIVER.get_archive_date(archive_id).strftime("%d/%m/%Y à %H:%M")
|
||||
|
||||
if not group_ids:
|
||||
# tous les inscrits du semestre
|
||||
group_ids = [sco_groups.get_default_group(formsemestre_id)]
|
||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||
group_ids, formsemestre_id=formsemestre_id
|
||||
)
|
||||
groups_filename = "-" + groups_infos.groups_filename
|
||||
etudids = [m["etudid"] for m in groups_infos.members]
|
||||
|
||||
# Tableau recap notes en XLS (pour tous les etudiants, n'utilise pas les groupes)
|
||||
data, _ = gen_formsemestre_recapcomplet_excel(res, include_evaluations=True)
|
||||
if data:
|
||||
PV_ARCHIVER.store(
|
||||
archive_id,
|
||||
"Tableau_moyennes" + scu.XLSX_SUFFIX,
|
||||
data,
|
||||
dept_id=formsemestre.dept_id,
|
||||
)
|
||||
# Tableau recap notes en HTML (pour tous les etudiants, n'utilise pas les groupes)
|
||||
table_html, _, _ = gen_formsemestre_recapcomplet_html_table(
|
||||
formsemestre, res, include_evaluations=True
|
||||
)
|
||||
if table_html:
|
||||
flash(f"Moyennes archivées le {date}", category="info")
|
||||
data = "\n".join(
|
||||
[
|
||||
html_sco_header.sco_header(
|
||||
page_title=f"Moyennes archivées le {date}",
|
||||
no_side_bar=True,
|
||||
),
|
||||
f'<h2 class="fontorange">Valeurs archivées le {date}</h2>',
|
||||
"""<style type="text/css">table.notes_recapcomplet tr { color: rgb(185,70,0); }
|
||||
</style>""",
|
||||
table_html,
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
)
|
||||
PV_ARCHIVER.store(
|
||||
archive_id, "Tableau_moyennes.html", data, dept_id=formsemestre.dept_id
|
||||
)
|
||||
|
||||
# Bulletins en JSON
|
||||
data = gen_formsemestre_recapcomplet_json(formsemestre_id, xml_with_decisions=True)
|
||||
data_js = json.dumps(data, indent=1, cls=ScoDocJSONEncoder)
|
||||
if data:
|
||||
PV_ARCHIVER.store(
|
||||
archive_id, "Bulletins.json", data_js, dept_id=formsemestre.dept_id
|
||||
)
|
||||
# Décisions de jury, en XLS
|
||||
if formsemestre.formation.is_apc():
|
||||
response = jury_but_pv.pvjury_page_but(formsemestre_id, fmt="xls")
|
||||
data = response.get_data()
|
||||
else: # formations classiques
|
||||
data = sco_pv_forms.formsemestre_pvjury(
|
||||
formsemestre_id, fmt="xls", publish=False
|
||||
)
|
||||
if data:
|
||||
PV_ARCHIVER.store(
|
||||
archive_id,
|
||||
"Decisions_Jury" + scu.XLSX_SUFFIX,
|
||||
data,
|
||||
dept_id=formsemestre.dept_id,
|
||||
)
|
||||
# Classeur bulletins (PDF)
|
||||
data, _ = sco_bulletins_pdf.get_formsemestre_bulletins_pdf(
|
||||
formsemestre_id, version=bul_version
|
||||
)
|
||||
if data:
|
||||
PV_ARCHIVER.store(
|
||||
archive_id,
|
||||
"Bulletins.pdf",
|
||||
data,
|
||||
dept_id=formsemestre.dept_id,
|
||||
)
|
||||
# Lettres individuelles (PDF):
|
||||
data = sco_pv_lettres_inviduelles.pdf_lettres_individuelles(
|
||||
formsemestre_id,
|
||||
etudids=etudids,
|
||||
date_jury=date_jury,
|
||||
date_commission=date_commission,
|
||||
signature=signature,
|
||||
)
|
||||
if data:
|
||||
PV_ARCHIVER.store(
|
||||
archive_id,
|
||||
f"CourriersDecisions{groups_filename}.pdf",
|
||||
data,
|
||||
dept_id=formsemestre.dept_id,
|
||||
)
|
||||
|
||||
# PV de jury (PDF):
|
||||
data = sco_pv_pdf.pvjury_pdf(
|
||||
formsemestre,
|
||||
etudids=etudids,
|
||||
date_commission=date_commission,
|
||||
date_jury=date_jury,
|
||||
numero_arrete=numero_arrete,
|
||||
code_vdi=code_vdi,
|
||||
show_title=show_title,
|
||||
pv_title_session=pv_title_session,
|
||||
pv_title=pv_title,
|
||||
with_paragraph_nom=with_paragraph_nom,
|
||||
anonymous=anonymous,
|
||||
)
|
||||
if data:
|
||||
PV_ARCHIVER.store(
|
||||
archive_id,
|
||||
f"PV_Jury{groups_filename}.pdf",
|
||||
data,
|
||||
dept_id=formsemestre.dept_id,
|
||||
)
|
||||
|
||||
|
||||
def formsemestre_archive(formsemestre_id, group_ids: list[int] = None):
|
||||
"""Make and store new archive for this formsemestre.
|
||||
(all students or only selected groups)
|
||||
"""
|
||||
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
if not formsemestre.can_edit_pv():
|
||||
raise ScoPermissionDenied(
|
||||
dest_url=url_for(
|
||||
"notes.formsemestre_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre_id,
|
||||
)
|
||||
)
|
||||
if not group_ids:
|
||||
# tous les inscrits du semestre
|
||||
group_ids = [sco_groups.get_default_group(formsemestre_id)]
|
||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||
group_ids, formsemestre_id=formsemestre_id
|
||||
)
|
||||
|
||||
H = [
|
||||
html_sco_header.html_sem_header(
|
||||
"Archiver les PV et résultats du semestre",
|
||||
javascripts=sco_groups_view.JAVASCRIPTS,
|
||||
cssstyles=sco_groups_view.CSSSTYLES,
|
||||
init_qtip=True,
|
||||
),
|
||||
"""<p class="help">Cette page permet de générer et d'archiver tous
|
||||
les documents résultant de ce semestre: PV de jury, lettres individuelles,
|
||||
tableaux récapitulatifs.</p><p class="help">Les documents archivés sont
|
||||
enregistrés et non modifiables, on peut les retrouver ultérieurement.
|
||||
</p><p class="help">On peut archiver plusieurs versions des documents
|
||||
(avant et après le jury par exemple).
|
||||
</p>
|
||||
""",
|
||||
]
|
||||
F = [
|
||||
f"""<p><em>Note: les documents sont aussi affectés par les réglages sur la page
|
||||
"<a class="stdlink" href="{
|
||||
url_for("scolar.edit_preferences", scodoc_dept=g.scodoc_dept)
|
||||
}">Paramétrage</a>"
|
||||
(accessible à l'administrateur du département).</em>
|
||||
</p>""",
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
|
||||
descr = [
|
||||
(
|
||||
"description",
|
||||
{"input_type": "textarea", "rows": 4, "cols": 77, "title": "Description"},
|
||||
),
|
||||
("sep", {"input_type": "separator", "title": "Informations sur PV de jury"}),
|
||||
]
|
||||
descr += sco_pv_forms.descrform_pvjury(formsemestre)
|
||||
descr += [
|
||||
(
|
||||
"signature",
|
||||
{
|
||||
"input_type": "file",
|
||||
"size": 30,
|
||||
"explanation": "optionnel: image scannée de la signature pour les lettres individuelles",
|
||||
},
|
||||
),
|
||||
(
|
||||
"bul_version",
|
||||
{
|
||||
"input_type": "menu",
|
||||
"title": "Version des bulletins archivés",
|
||||
"labels": [
|
||||
"Version courte",
|
||||
"Version intermédiaire",
|
||||
"Version complète",
|
||||
],
|
||||
"allowed_values": scu.BULLETINS_VERSIONS.keys(),
|
||||
"default": "long",
|
||||
},
|
||||
),
|
||||
]
|
||||
menu_choix_groupe = (
|
||||
"""<div class="group_ids_sel_menu">Groupes d'étudiants à lister: """
|
||||
+ sco_groups_view.menu_groups_choice(groups_infos)
|
||||
+ """(pour les PV et lettres)</div>"""
|
||||
)
|
||||
|
||||
tf = TrivialFormulator(
|
||||
request.base_url,
|
||||
scu.get_request_args(),
|
||||
descr,
|
||||
cancelbutton="Annuler",
|
||||
submitlabel="Générer et archiver les documents",
|
||||
name="tf",
|
||||
formid="group_selector",
|
||||
html_foot_markup=menu_choix_groupe,
|
||||
)
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + "\n" + tf[1] + "\n".join(F)
|
||||
elif tf[0] == -1:
|
||||
msg = "Opération annulée"
|
||||
else:
|
||||
# submit
|
||||
sf = tf[2]["signature"]
|
||||
signature = sf.read() # image of signature
|
||||
if tf[2]["anonymous"]:
|
||||
tf[2]["anonymous"] = True
|
||||
else:
|
||||
tf[2]["anonymous"] = False
|
||||
do_formsemestre_archive(
|
||||
formsemestre_id,
|
||||
group_ids=group_ids,
|
||||
description=tf[2]["description"],
|
||||
date_jury=tf[2]["date_jury"],
|
||||
date_commission=tf[2]["date_commission"],
|
||||
signature=signature,
|
||||
numero_arrete=tf[2]["numero_arrete"],
|
||||
code_vdi=tf[2]["code_vdi"],
|
||||
pv_title_session=tf[2]["pv_title_session"],
|
||||
pv_title=tf[2]["pv_title"],
|
||||
show_title=tf[2]["show_title"],
|
||||
with_paragraph_nom=tf[2]["with_paragraph_nom"],
|
||||
anonymous=tf[2]["anonymous"],
|
||||
bul_version=tf[2]["bul_version"],
|
||||
)
|
||||
msg = "Nouvelle archive créée"
|
||||
|
||||
# submitted or cancelled:
|
||||
flash(msg)
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.formsemestre_list_archives",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre_id,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def formsemestre_list_archives(formsemestre_id):
|
||||
"""Page listing archives"""
|
||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||
sem_archive_id = formsemestre_id
|
||||
L = []
|
||||
for archive_id in PV_ARCHIVER.list_obj_archives(
|
||||
sem_archive_id, dept_id=formsemestre.dept_id
|
||||
):
|
||||
a = {
|
||||
"archive_id": archive_id,
|
||||
"description": PV_ARCHIVER.get_archive_description(
|
||||
archive_id, dept_id=formsemestre.dept_id
|
||||
),
|
||||
"date": PV_ARCHIVER.get_archive_date(archive_id),
|
||||
"content": PV_ARCHIVER.list_archive(
|
||||
archive_id, dept_id=formsemestre.dept_id
|
||||
),
|
||||
}
|
||||
L.append(a)
|
||||
|
||||
H = [html_sco_header.html_sem_header("Archive des PV et résultats ")]
|
||||
if not L:
|
||||
H.append("<p>aucune archive enregistrée</p>")
|
||||
else:
|
||||
H.append("<ul>")
|
||||
for a in L:
|
||||
archive_name = PV_ARCHIVER.get_archive_name(a["archive_id"])
|
||||
H.append(
|
||||
'<li>%s : <em>%s</em> (<a href="formsemestre_delete_archive?formsemestre_id=%s&archive_name=%s">supprimer</a>)<ul>'
|
||||
% (
|
||||
a["date"].strftime("%d/%m/%Y %H:%M"),
|
||||
a["description"],
|
||||
formsemestre_id,
|
||||
archive_name,
|
||||
)
|
||||
)
|
||||
for filename in a["content"]:
|
||||
H.append(
|
||||
'<li><a href="formsemestre_get_archived_file?formsemestre_id=%s&archive_name=%s&filename=%s">%s</a></li>'
|
||||
% (formsemestre_id, archive_name, filename, filename)
|
||||
)
|
||||
if not a["content"]:
|
||||
H.append("<li><em>aucun fichier !</em></li>")
|
||||
H.append("</ul></li>")
|
||||
H.append("</ul>")
|
||||
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def formsemestre_get_archived_file(formsemestre_id, archive_name, filename):
|
||||
"""Send file to client."""
|
||||
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
sem_archive_id = formsemestre.id
|
||||
return PV_ARCHIVER.get_archived_file(
|
||||
sem_archive_id, archive_name, filename, dept_id=formsemestre.dept_id
|
||||
)
|
||||
|
||||
|
||||
def formsemestre_delete_archive(formsemestre_id, archive_name, dialog_confirmed=False):
|
||||
"""Delete an archive"""
|
||||
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
if not formsemestre.can_edit_pv():
|
||||
raise ScoPermissionDenied(
|
||||
dest_url=url_for(
|
||||
"notes.formsemestre_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre_id,
|
||||
)
|
||||
)
|
||||
sem_archive_id = formsemestre_id
|
||||
archive_id = PV_ARCHIVER.get_id_from_name(
|
||||
sem_archive_id, archive_name, dept_id=formsemestre.dept_id
|
||||
)
|
||||
|
||||
dest_url = url_for(
|
||||
"notes.formsemestre_list_archives",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre_id,
|
||||
)
|
||||
|
||||
if not dialog_confirmed:
|
||||
return scu.confirm_dialog(
|
||||
f"""<h2>Confirmer la suppression de l'archive du {
|
||||
PV_ARCHIVER.get_archive_date(archive_id).strftime("%d/%m/%Y %H:%M")
|
||||
} ?</h2>
|
||||
<p>La suppression sera définitive.</p>
|
||||
""",
|
||||
dest_url="",
|
||||
cancel_url=dest_url,
|
||||
parameters={
|
||||
"formsemestre_id": formsemestre_id,
|
||||
"archive_name": archive_name,
|
||||
},
|
||||
)
|
||||
|
||||
PV_ARCHIVER.delete_archive(archive_id, dept_id=formsemestre.dept_id)
|
||||
flash("Archive supprimée")
|
||||
return flask.redirect(dest_url)
|
||||
|
@ -16,7 +16,9 @@ from app import log
|
||||
|
||||
|
||||
class Trace:
|
||||
"""gestionnaire de la trace des fichiers justificatifs"""
|
||||
"""gestionnaire de la trace des fichiers justificatifs
|
||||
XXX TODO à documenter: rôle et format des fichier strace
|
||||
"""
|
||||
|
||||
def __init__(self, path: str) -> None:
|
||||
self.path: str = path + "/_trace.csv"
|
||||
@ -157,15 +159,15 @@ class JustificatifArchiver(BaseArchiver):
|
||||
Si trace == True : sauvegarde le nom du/des fichier(s) supprimé(s)
|
||||
dans la trace de l'étudiant
|
||||
"""
|
||||
print("debug : ", archive_name, filename, has_trace)
|
||||
log(f"debug : {archive_name}{filename} {has_trace}")
|
||||
if str(etud.id) not in self.list_oids(etud.dept_id):
|
||||
raise ValueError(f"Aucune archive pour etudid[{etud.id}]")
|
||||
try:
|
||||
archive_id = self.get_id_from_name(
|
||||
etud.id, archive_name, dept_id=etud.dept_id
|
||||
)
|
||||
except ScoValueError:
|
||||
raise ValueError(f"Archive Inconnue [{archive_name}]")
|
||||
except ScoValueError as exc:
|
||||
raise ValueError(f"Archive Inconnue [{archive_name}]") from exc
|
||||
|
||||
if filename is not None:
|
||||
if filename not in self.list_archive(archive_id, dept_id=etud.dept_id):
|
||||
@ -183,6 +185,7 @@ class JustificatifArchiver(BaseArchiver):
|
||||
trace = Trace(archive_id)
|
||||
trace.set_trace(filename, mode="delete")
|
||||
os.remove(path)
|
||||
log(f"delete_justificatif: removed {path}")
|
||||
|
||||
else:
|
||||
if has_trace:
|
||||
@ -197,12 +200,14 @@ class JustificatifArchiver(BaseArchiver):
|
||||
archive_id,
|
||||
)
|
||||
)
|
||||
log(f"delete_justificatif: deleted archive {archive_id}")
|
||||
|
||||
def list_justificatifs(
|
||||
self, archive_name: str, etud: Identite
|
||||
) -> list[tuple[str, int]]:
|
||||
"""
|
||||
Retourne la liste des noms de fichiers dans l'archive donnée
|
||||
avec l'uid de l'utilisateur ayant saisi le fichier.
|
||||
"""
|
||||
filenames: list[str] = []
|
||||
archive_id = self.get_id_from_name(etud.id, archive_name, dept_id=etud.dept_id)
|
||||
@ -210,9 +215,8 @@ class JustificatifArchiver(BaseArchiver):
|
||||
filenames = self.list_archive(archive_id, dept_id=etud.dept_id)
|
||||
trace: Trace = Trace(archive_id)
|
||||
traced = trace.get_trace(filenames)
|
||||
retour = [(key, value[2]) for key, value in traced.items()]
|
||||
|
||||
return retour
|
||||
return [(key, value[2]) for key, value in traced.items()]
|
||||
|
||||
def get_justificatif_file(self, archive_name: str, etud: Identite, filename: str):
|
||||
"""
|
||||
|
@ -427,7 +427,7 @@ def create_absence(
|
||||
db.session.commit()
|
||||
if est_just:
|
||||
justi = Justificatif.create_justificatif(
|
||||
etud=etud,
|
||||
etudiant=etud,
|
||||
date_debut=date_debut,
|
||||
date_fin=date_fin,
|
||||
etat=scu.EtatJustificatif.VALIDE,
|
||||
|
@ -115,7 +115,9 @@ _EVENT_DEFAULT_COLOR = "rgb(214, 233, 248)"
|
||||
|
||||
|
||||
def formsemestre_edt_dict(
|
||||
formsemestre: FormSemestre, group_ids: list[int] = None
|
||||
formsemestre: FormSemestre,
|
||||
group_ids: list[int] = None,
|
||||
show_modules_titles=True,
|
||||
) -> list[dict]:
|
||||
"""EDT complet du semestre, comme une liste de dict serialisable en json.
|
||||
Fonction appelée par l'API /formsemestre/<int:formsemestre_id>/edt
|
||||
@ -126,10 +128,12 @@ def formsemestre_edt_dict(
|
||||
"""
|
||||
group_ids_set = set(group_ids) if group_ids else set()
|
||||
try:
|
||||
events_scodoc = _load_and_convert_ics(formsemestre)
|
||||
events_scodoc, _ = load_and_convert_ics(formsemestre)
|
||||
except ScoValueError as exc:
|
||||
return exc.args[0]
|
||||
# Génération des événements pour le calendrier html
|
||||
promo_icon = f"""<img height="24px" src="{scu.STATIC_DIR}/icons/promo.svg"
|
||||
title="promotion complète" alt="promotion"/>"""
|
||||
events_cal = []
|
||||
for event in events_scodoc:
|
||||
group: GroupDescr | bool = event["group"]
|
||||
@ -140,7 +144,7 @@ def formsemestre_edt_dict(
|
||||
</div>"""
|
||||
else:
|
||||
group_disp = (
|
||||
f"""<div class="group-name">{group.get_nom_with_part(default="promo")}</div>"""
|
||||
f"""<div class="group-name">{group.get_nom_with_part(default=promo_icon)}</div>"""
|
||||
if group
|
||||
else f"""<div class="group-edt">{event['edt_group']}
|
||||
<span title="vérifier noms de groupe ou configuration extraction edt">
|
||||
@ -173,13 +177,14 @@ def formsemestre_edt_dict(
|
||||
scu.EMO_WARNING} {event['edt_module']}</span>"""
|
||||
bubble = "code module non trouvé dans ScoDoc. Vérifier configuration."
|
||||
case _: # module EDT bien retrouvé dans ScoDoc
|
||||
mod_disp = f"""<span class="mod-name mod-code" title="{
|
||||
modimpl.module.abbrev or ""} ({event['edt_module']})">{
|
||||
modimpl.module.code}</span>"""
|
||||
bubble = f"{modimpl.module.abbrev or ''} ({event['edt_module']})"
|
||||
|
||||
title = f"""<div class = "module-edt" title="{bubble} {event['title_edt']}">
|
||||
<a class="discretelink" href="{url_abs or ''}">{mod_disp} <span>{event['title']}</span></a>
|
||||
bubble = f"{modimpl.module.abbrev or modimpl.module.titre or ''} ({event['edt_module']})"
|
||||
mod_disp = (
|
||||
f"""<span class="mod-name mod-code">{modimpl.module.code}</span>"""
|
||||
)
|
||||
# {event['title_edt']}
|
||||
span_title = f" <span>{event['title']}</span>" if show_modules_titles else ""
|
||||
title = f"""<div class = "module-edt" title="{bubble}">
|
||||
<a class="discretelink" href="{url_abs or ''}">{mod_disp}{span_title}</a>
|
||||
</div>
|
||||
"""
|
||||
|
||||
@ -208,8 +213,15 @@ def formsemestre_edt_dict(
|
||||
return events_cal
|
||||
|
||||
|
||||
def _load_and_convert_ics(formsemestre: FormSemestre) -> list[dict]:
|
||||
"chargement fichier, filtrage et extraction des identifiants."
|
||||
def load_and_convert_ics(formsemestre: FormSemestre) -> tuple[list[dict], list[str]]:
|
||||
"""Chargement fichier ics, filtrage et extraction des identifiants.
|
||||
Renvoie une liste d'évènements, et la liste des identifiants de groupes
|
||||
trouvés (utilisée pour l'aide).
|
||||
|
||||
Groupes:
|
||||
- False si extraction regexp non configuré
|
||||
- "tous" (promo) si pas de correspondance trouvée.
|
||||
"""
|
||||
# Chargement du calendier ics
|
||||
_, calendar = formsemestre_load_calendar(formsemestre)
|
||||
if not calendar:
|
||||
@ -251,6 +263,7 @@ def _load_and_convert_ics(formsemestre: FormSemestre) -> list[dict]:
|
||||
group_name: _COLOR_PALETTE[i % (len(_COLOR_PALETTE) - 1) + 1]
|
||||
for i, group_name in enumerate(edt2group)
|
||||
}
|
||||
edt_groups_ids = set() # les ids de groupes tels que dans l'ics
|
||||
default_group = formsemestre.get_default_group()
|
||||
edt2modimpl = formsemestre_retreive_modimpls_from_edt_id(formsemestre)
|
||||
# ---
|
||||
@ -271,6 +284,7 @@ def _load_and_convert_ics(formsemestre: FormSemestre) -> list[dict]:
|
||||
edt_group = extract_event_data(
|
||||
event, edt_ics_group_field, edt_ics_group_pattern
|
||||
)
|
||||
edt_groups_ids.add(edt_group)
|
||||
# si pas de groupe dans l'event, ou si groupe non reconnu,
|
||||
# prend toute la promo ("tous")
|
||||
group: GroupDescr = (
|
||||
@ -324,7 +338,7 @@ def _load_and_convert_ics(formsemestre: FormSemestre) -> list[dict]:
|
||||
"end": event.decoded("dtend").isoformat(),
|
||||
}
|
||||
)
|
||||
return events_sco
|
||||
return events_sco, sorted(edt_groups_ids)
|
||||
|
||||
|
||||
def extract_event_data(
|
||||
|
@ -56,12 +56,11 @@ from app.scodoc.sco_utils import ModuleType
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from app.scodoc.sco_exceptions import (
|
||||
ScoValueError,
|
||||
ScoInvalidDateError,
|
||||
ScoInvalidIdType,
|
||||
)
|
||||
from app.scodoc import html_sco_header
|
||||
from app.scodoc import htmlutils
|
||||
from app.scodoc import sco_archives
|
||||
from app.scodoc import sco_archives_formsemestre
|
||||
from app.scodoc import sco_bulletins
|
||||
from app.scodoc import codes_cursus
|
||||
from app.scodoc import sco_compute_moy
|
||||
@ -454,7 +453,9 @@ def formsemestre_status_menubar(formsemestre: FormSemestre) -> str:
|
||||
"title": "Documents archivés",
|
||||
"endpoint": "notes.formsemestre_list_archives",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": sco_archives.PV_ARCHIVER.list_obj_archives(formsemestre_id),
|
||||
"enabled": sco_archives_formsemestre.PV_ARCHIVER.list_obj_archives(
|
||||
formsemestre_id
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
--color-justi-clair: #48f6ff;
|
||||
--color-justi-attente: yellow;
|
||||
--color-justi-attente-stripe: #29b990; /* pink #fa25cb; */ /* #789dbb;*/
|
||||
--color-justi-modifie: rgb(255, 230, 0);
|
||||
--color-justi-invalide: #a84476;
|
||||
--color-nonwork: #badfff;
|
||||
|
||||
@ -645,7 +646,7 @@
|
||||
.assi-liste {
|
||||
border: 1px solid gray;
|
||||
border-radius: 12px;
|
||||
margin-right: 12px;
|
||||
margin-right: 24px;
|
||||
padding: 12px;
|
||||
}
|
||||
#options-tableau label {
|
||||
@ -694,6 +695,9 @@ tr.row-justificatif.valide td.assi-type {
|
||||
tr.row-justificatif.attente td.assi-type {
|
||||
background-color: var(--color-justi-attente);
|
||||
}
|
||||
tr.row-justificatif.modifie td.assi-type {
|
||||
background-color: var(--color-justi-modifie);
|
||||
}
|
||||
tr.row-justificatif.non_valide td.assi-type {
|
||||
background-color: var(--color-justi-invalide);
|
||||
}
|
||||
|
@ -1,3 +1,8 @@
|
||||
#show_modules_titles_form {
|
||||
display: inline-block;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.toastui-calendar-template-time {
|
||||
padding: 4px;
|
||||
word-break: break-all;
|
||||
|
140
app/static/icons/promo.svg
Normal file
140
app/static/icons/promo.svg
Normal file
@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<ellipse style="fill:#F1DBC8;" cx="194.5" cy="111.67" rx="35.396" ry="35.671"/>
|
||||
<ellipse style="fill:#F1DBC8;" cx="317.5" cy="111.67" rx="35.396" ry="35.671"/>
|
||||
</g>
|
||||
<path style="fill:#FF916C;" d="M250.277,172.685c-8.091-15.056-23.918-25.342-42.015-25.342H194.5h-13.764
|
||||
c-18.097,0-33.924,10.286-42.014,25.342c16.826,2.757,29.673,17.471,29.673,35.208c0,19.701-15.848,35.671-35.395,35.671h13.763
|
||||
c18.097,0,33.925,10.286,42.014,25.339c1.863-0.305,3.774-0.464,5.724-0.464c1.948,0,3.86,0.159,5.723,0.467
|
||||
c8.09-15.056,23.917-25.342,42.014-25.342H256c-19.549,0-35.397-15.97-35.397-35.671
|
||||
C220.603,190.155,233.449,175.441,250.277,172.685z"/>
|
||||
<path style="fill:#C22C65;" d="M303.736,147.343c-18.097,0-33.924,10.286-42.014,25.342c16.827,2.757,29.673,17.471,29.673,35.208
|
||||
c0,19.701-15.848,35.671-35.395,35.671h13.763c18.097,0,33.924,10.286,42.014,25.339c1.863-0.305,3.774-0.464,5.724-0.464
|
||||
c1.948,0,3.859,0.159,5.723,0.467c8.09-15.056,23.917-25.342,42.014-25.342H379c-19.549,0-35.396-15.97-35.396-35.671
|
||||
c0-17.737,12.846-32.451,29.673-35.208c-8.091-15.056-23.918-25.342-42.015-25.342H317.5L303.736,147.343L303.736,147.343z"/>
|
||||
<g>
|
||||
<path style="fill:#F1DBC8;" d="M168.395,207.893c0-17.737-12.847-32.451-29.673-35.208c-1.863-0.306-3.774-0.464-5.723-0.464
|
||||
c-19.549,0-35.396,15.971-35.396,35.672s15.847,35.671,35.396,35.671S168.395,227.594,168.395,207.893z"/>
|
||||
<path style="fill:#F1DBC8;" d="M250.277,172.685c-16.828,2.757-29.674,17.471-29.674,35.208c0,19.701,15.848,35.671,35.397,35.671
|
||||
c19.548,0,35.395-15.97,35.395-35.671c0-17.737-12.846-32.451-29.673-35.208c-1.863-0.306-3.775-0.464-5.723-0.464
|
||||
C254.052,172.221,252.14,172.379,250.277,172.685z"/>
|
||||
<path style="fill:#F1DBC8;" d="M373.277,172.685c-16.827,2.757-29.673,17.471-29.673,35.208c0,19.701,15.847,35.671,35.396,35.671
|
||||
c19.548,0,35.396-15.97,35.396-35.671S398.548,172.221,379,172.221C377.052,172.221,375.14,172.379,373.277,172.685z"/>
|
||||
</g>
|
||||
<path style="fill:#55CD8E;" d="M188.776,268.902c-8.089-15.053-23.917-25.339-42.014-25.339H133h-13.764
|
||||
c-18.097,0-33.924,10.286-42.014,25.339c16.827,2.758,29.673,17.471,29.673,35.208c0,19.701-15.848,35.672-35.395,35.672h13.763
|
||||
c26.256,0,47.737,21.648,47.737,48.108c0-26.46,21.481-48.108,47.736-48.108H194.5c-19.549,0-35.397-15.971-35.397-35.672
|
||||
C159.103,286.373,171.949,271.66,188.776,268.902z"/>
|
||||
<path style="fill:#876E67;" d="M242.236,243.564c-18.097,0-33.924,10.286-42.014,25.339c16.827,2.758,29.672,17.471,29.672,35.208
|
||||
c0,19.701-15.847,35.672-35.394,35.672h13.763c26.255,0,47.737,21.648,47.737,48.108c0-26.46,21.481-48.108,47.736-48.108H317.5
|
||||
c-19.549,0-35.396-15.971-35.396-35.672c0-17.737,12.845-32.45,29.672-35.205c-8.09-15.056-23.917-25.342-42.014-25.342H256
|
||||
L242.236,243.564L242.236,243.564z"/>
|
||||
<path style="fill:#4BC1D7;" d="M323.223,268.902c16.827,2.758,29.673,17.471,29.673,35.208c0,19.701-15.848,35.672-35.396,35.672
|
||||
h13.763c26.256,0,47.737,21.648,47.737,48.108c0-26.46,21.481-48.108,47.736-48.108H440.5c-19.549,0-35.397-15.971-35.397-35.672
|
||||
c0-17.737,12.846-32.45,29.674-35.205c-8.091-15.056-23.918-25.342-42.015-25.342H379h-13.764
|
||||
C347.14,243.564,331.313,253.85,323.223,268.902z"/>
|
||||
<g>
|
||||
<path style="fill:#F1DBC8;" d="M71.5,339.782c19.548,0,35.395-15.971,35.395-35.672c0-17.737-12.846-32.45-29.673-35.208
|
||||
c-1.863-0.305-3.774-0.464-5.723-0.464c-19.549,0-35.396,15.972-35.396,35.672C36.104,323.812,51.951,339.782,71.5,339.782z"/>
|
||||
<path style="fill:#F1DBC8;" d="M159.103,304.11c0,19.701,15.848,35.672,35.397,35.672c19.548,0,35.394-15.971,35.394-35.672
|
||||
c0-17.737-12.845-32.45-29.672-35.208c-1.862-0.305-3.774-0.464-5.723-0.464s-3.86,0.159-5.724,0.464
|
||||
C171.949,271.66,159.103,286.373,159.103,304.11z"/>
|
||||
<path style="fill:#F1DBC8;" d="M282.104,304.11c0,19.701,15.847,35.672,35.396,35.672c19.548,0,35.396-15.971,35.396-35.672
|
||||
c0-17.737-12.846-32.45-29.673-35.208c-1.863-0.305-3.774-0.464-5.723-0.464s-3.86,0.159-5.724,0.467
|
||||
C294.949,271.66,282.104,286.373,282.104,304.11z"/>
|
||||
<path style="fill:#F1DBC8;" d="M405.103,304.11c0,19.701,15.848,35.672,35.397,35.672c19.548,0,35.395-15.971,35.395-35.672
|
||||
c0-19.7-15.847-35.672-35.395-35.672c-1.949,0-3.86,0.159-5.723,0.467C417.949,271.66,405.103,286.373,405.103,304.11z"/>
|
||||
</g>
|
||||
<path style="fill:#BDD377;" d="M426.736,339.782c-26.255,0-47.736,21.648-47.736,48.108V436h123v-48.109
|
||||
c0-26.46-21.482-48.108-47.737-48.108H440.5L426.736,339.782L426.736,339.782z"/>
|
||||
<path style="fill:#FFBD50;" d="M379,387.891c0-26.46-21.481-48.108-47.737-48.108H317.5h-13.764
|
||||
c-26.255,0-47.736,21.648-47.736,48.108V436h123V387.891z"/>
|
||||
<path style="fill:#76C8D6;" d="M256,387.891c0-26.46-21.482-48.108-47.737-48.108H194.5h-13.764
|
||||
c-26.255,0-47.736,21.648-47.736,48.108V436h123V387.891z"/>
|
||||
<path style="fill:#F13D7C;" d="M133,387.891c0-26.46-21.481-48.108-47.737-48.108H71.5H57.736
|
||||
C31.481,339.782,10,361.431,10,387.891V436h123V387.891z"/>
|
||||
</g>
|
||||
<path d="M432.234,388.82h-0.236c-5.522,0-10,4.478-10,10s4.478,10,10,10h0.236c5.522,0,10-4.478,10-10
|
||||
S437.757,388.82,432.234,388.82z"/>
|
||||
<path d="M501.999,446c5.523,0,10-4.478,10-10v-37.162c0-0.007,0.001-0.013,0.001-0.02s-0.001-0.013-0.001-0.02V387.89
|
||||
c0-24.602-15.375-45.666-37.015-54.129c6.793-7.986,10.91-18.341,10.91-29.651c0-25.184-20.364-45.672-45.395-45.672
|
||||
c-0.145,0-0.287,0.01-0.431,0.011c-6.659-9.589-15.928-16.842-26.524-20.975c6.758-7.977,10.851-18.305,10.851-29.582
|
||||
c0-25.184-20.364-45.672-45.396-45.672c-0.144,0-0.285,0.01-0.429,0.011c-6.659-9.591-15.929-16.845-26.526-20.978
|
||||
c6.758-7.977,10.851-18.305,10.851-29.583C362.896,86.488,342.531,66,317.5,66s-45.396,20.488-45.396,45.671
|
||||
c0,11.278,4.093,21.607,10.851,29.583c-10.599,4.133-19.867,11.387-26.527,20.978c-0.143-0.001-0.285-0.011-0.428-0.011
|
||||
c-0.144,0-0.286,0.01-0.429,0.011c-6.66-9.591-15.929-16.845-26.527-20.978c6.758-7.977,10.851-18.305,10.851-29.583
|
||||
C239.894,86.488,219.531,66,194.5,66c-25.032,0-45.397,20.488-45.397,45.671c0,11.278,4.093,21.607,10.851,29.583
|
||||
c-10.598,4.133-19.867,11.387-26.526,20.978c-0.143-0.001-0.285-0.011-0.428-0.011c-25.031,0-45.396,20.488-45.396,45.672
|
||||
c0,11.277,4.093,21.605,10.851,29.582c-10.597,4.133-19.866,11.385-26.525,20.975c-0.144-0.001-0.286-0.011-0.43-0.011
|
||||
c-25.031,0-45.396,20.488-45.396,45.672c0,11.31,4.117,21.665,10.911,29.651C15.375,342.225,0,363.289,0,387.891V436
|
||||
c0,5.522,4.477,10,10,10H501.999 M465.895,304.11c0,14.155-11.392,25.671-25.395,25.671c-14.004,0-25.397-11.516-25.397-25.671
|
||||
s11.393-25.672,25.397-25.672C454.503,278.439,465.895,289.955,465.895,304.11z M395.103,304.11c0,11.31,4.117,21.665,10.911,29.651
|
||||
c-11.037,4.316-20.448,11.9-27.015,21.574c-6.566-9.674-15.978-17.258-27.015-21.574c6.793-7.986,10.91-18.341,10.91-29.651
|
||||
c0-17.234-9.54-32.266-23.584-40.041c6.92-6.64,16.14-10.506,25.925-10.506h27.526c9.785,0,19.006,3.866,25.925,10.506
|
||||
C404.645,271.845,395.103,286.876,395.103,304.11z M256,355.336c-6.567-9.674-15.979-17.259-27.016-21.574
|
||||
c6.793-7.986,10.91-18.341,10.91-29.651c0-17.234-9.539-32.266-23.583-40.04c6.92-6.641,16.14-10.507,25.925-10.507h27.526
|
||||
c9.785,0,19.005,3.866,25.925,10.507c-14.044,7.774-23.584,22.806-23.584,40.04c0,11.31,4.117,21.665,10.911,29.651
|
||||
C271.977,338.078,262.566,345.662,256,355.336z M169.103,304.11c0-14.155,11.393-25.672,25.397-25.672
|
||||
c14.002,0,25.394,11.517,25.394,25.672s-11.392,25.671-25.394,25.671C180.497,329.781,169.103,318.266,169.103,304.11z M256,182.221
|
||||
c14.003,0,25.395,11.517,25.395,25.672S270.002,233.564,256,233.564c-14.003,0-25.396-11.516-25.396-25.671
|
||||
C230.604,193.737,241.997,182.221,256,182.221z M292.103,304.11c0-14.155,11.393-25.672,25.397-25.672
|
||||
c14.003,0,25.396,11.517,25.396,25.672s-11.393,25.671-25.396,25.671C303.496,329.781,292.103,318.266,292.103,304.11z
|
||||
M404.396,207.893c0,14.155-11.393,25.671-25.396,25.671s-25.396-11.516-25.396-25.671s11.393-25.672,25.396-25.672
|
||||
S404.396,193.737,404.396,207.893z M317.5,86c14.003,0,25.396,11.516,25.396,25.671s-11.393,25.672-25.396,25.672
|
||||
s-25.396-11.517-25.396-25.672S303.497,86,317.5,86z M303.736,157.343h27.526c9.786,0,19.007,3.867,25.927,10.508
|
||||
c-14.044,7.774-23.585,22.807-23.585,40.042c0,11.277,4.093,21.605,10.851,29.582c-10.598,4.133-19.865,11.385-26.524,20.975
|
||||
c-0.144-0.001-0.286-0.011-0.431-0.011s-0.287,0.01-0.432,0.011c-6.659-9.589-15.927-16.842-26.524-20.975
|
||||
c6.758-7.977,10.851-18.305,10.851-29.582c0-17.235-9.541-32.268-23.586-40.042C284.729,161.21,293.95,157.343,303.736,157.343z
|
||||
M194.5,86c14.002,0,25.394,11.516,25.394,25.671s-11.392,25.672-25.394,25.672c-14.003,0-25.397-11.517-25.397-25.672
|
||||
S180.497,86,194.5,86z M180.736,157.343h27.526c9.786,0,19.007,3.867,25.927,10.509c-14.045,7.773-23.585,22.806-23.585,40.041
|
||||
c0,11.277,4.093,21.605,10.851,29.582c-10.597,4.133-19.866,11.385-26.525,20.975c-0.144-0.001-0.286-0.011-0.43-0.011
|
||||
c-0.145,0-0.286,0.01-0.43,0.011c-6.659-9.59-15.928-16.842-26.525-20.975c6.758-7.977,10.851-18.305,10.851-29.582
|
||||
c0-17.235-9.541-32.268-23.585-40.042C161.729,161.21,170.951,157.343,180.736,157.343z M133,182.221
|
||||
c14.003,0,25.395,11.517,25.395,25.672S147.002,233.564,133,233.564c-14.003,0-25.396-11.516-25.396-25.671
|
||||
C107.604,193.737,118.997,182.221,133,182.221z M119.236,253.564h27.526c9.786,0,19.006,3.866,25.925,10.506
|
||||
c-14.044,7.774-23.585,22.807-23.585,40.041c0,11.31,4.117,21.666,10.911,29.651c-11.037,4.316-20.448,11.9-27.015,21.574
|
||||
c-6.567-9.674-15.978-17.258-27.015-21.574c6.794-7.986,10.911-18.341,10.911-29.651c0-17.234-9.54-32.266-23.584-40.041
|
||||
C100.231,257.43,109.451,253.564,119.236,253.564z M71.5,278.439c14.003,0,25.395,11.517,25.395,25.672S85.502,329.782,71.5,329.782
|
||||
c-14.003,0-25.396-11.516-25.396-25.671C46.104,289.955,57.497,278.439,71.5,278.439z M20,408.818h31.035c5.523,0,10-4.477,10-10
|
||||
c0-5.522-4.477-10-10-10H20v-0.928c0-21.014,17.096-38.109,38.109-38.109H84.89c21.014,0,38.109,17.096,38.109,38.109V426H20
|
||||
V408.818z M143,387.891c0-21.014,17.096-38.109,38.109-38.109h26.781c21.014,0,38.109,17.096,38.109,38.109V426H143V387.891z
|
||||
M266,387.891c0-21.014,17.096-38.109,38.108-38.109h26.782c21.014,0,38.109,17.096,38.109,38.109V426H266V387.891z M389,426
|
||||
v-38.109c0-21.014,17.096-38.109,38.109-38.109h26.781c21.013,0,38.108,17.096,38.108,38.109v0.928h-31.034c-5.522,0-10,4.478-10,10
|
||||
c0,5.523,4.478,10,10,10h31.034V426H389z"/>
|
||||
<path d="M80.001,388.82h-0.235c-5.523,0-10,4.478-10,10s4.477,10,10,10h0.235c5.523,0,10-4.478,10-10S85.524,388.82,80.001,388.82z"
|
||||
/>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 11 KiB |
@ -277,8 +277,10 @@ class RowAssiJusti(tb.Row):
|
||||
self.add_cell(
|
||||
"entry_date",
|
||||
"Saisie le",
|
||||
self.ligne["entry_date"].strftime("%d/%m/%y à %H:%M"),
|
||||
data={"order": self.ligne["entry_date"]},
|
||||
self.ligne["entry_date"].strftime("%d/%m/%y à %H:%M")
|
||||
if self.ligne["entry_date"]
|
||||
else "?",
|
||||
data={"order": self.ligne["entry_date"] or ""},
|
||||
raw_content=self.ligne["entry_date"],
|
||||
classes=["small-font"],
|
||||
column_classes={"entry_date"},
|
||||
@ -387,13 +389,20 @@ class RowAssiJusti(tb.Row):
|
||||
html.append(f'<a title="Détails" href="{url}">ℹ️</a>')
|
||||
|
||||
# Modifier
|
||||
url = url_for(
|
||||
"assiduites.tableau_assiduite_actions",
|
||||
type=self.ligne["type"],
|
||||
action="modifier",
|
||||
obj_id=self.ligne["obj_id"],
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
if self.ligne["type"] == "justificatif":
|
||||
url = url_for(
|
||||
"assiduites.edit_justificatif_etud",
|
||||
justif_id=self.ligne["obj_id"],
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
else:
|
||||
url = url_for(
|
||||
"assiduites.tableau_assiduite_actions",
|
||||
type=self.ligne["type"],
|
||||
action="modifier",
|
||||
obj_id=self.ligne["obj_id"],
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
html.append(f'<a title="Modifier" href="{url}">📝</a>')
|
||||
|
||||
# Supprimer
|
||||
|
68
app/templates/assiduites/explication_etats_justifs.j2
Normal file
68
app/templates/assiduites/explication_etats_justifs.j2
Normal file
@ -0,0 +1,68 @@
|
||||
{# Explication des états des justificatifs #}
|
||||
|
||||
<div class="explication-etats-justifs">
|
||||
<div class="explication-titre">États des justificatifs</div>
|
||||
<div class="explication-etats">
|
||||
<div class="valide">Justificatif valide</div>
|
||||
<div class="legend">ayant été considéré comme valide, justifie les absences
|
||||
ou retards de la période
|
||||
</div>
|
||||
|
||||
<div class="attente">Justificatif soumis</div>
|
||||
<div class="legend">en attente de validation. Les absences ne sont pas
|
||||
encore considérées comme justifiées.
|
||||
</div>
|
||||
|
||||
<div class="modifie">Justificatif modifié</div>
|
||||
<div class="legend">une information a été ajoutée ou modifiée. Doit être validé avant
|
||||
d'être pris en en compte.
|
||||
</div>
|
||||
|
||||
<div class="invalide">Justificatif invalide</div>
|
||||
<div class="legend">proposé mais considéré comme non valide.
|
||||
Les absences ne sont pas justifiées.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.explication-etats-justifs {
|
||||
margin-top: 32px;
|
||||
margin-left: 12px;
|
||||
padding: 8px;
|
||||
}
|
||||
.explication-etats-justifs .explication-titre {
|
||||
font-size: 110%;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.explication-etats-justifs .explication-etats {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
font-size: 80%;
|
||||
}
|
||||
.explication-etats > div {
|
||||
margin-bottom: 8px;
|
||||
margin-right: 8px;
|
||||
padding: 6px;
|
||||
}
|
||||
.explication-etats-justifs div.legend {
|
||||
font-style: italic;
|
||||
}
|
||||
.valide {
|
||||
background-color: var(--color-justi);
|
||||
}
|
||||
.attente {
|
||||
background-color: var(--color-justi-attente);
|
||||
}
|
||||
.modifie {
|
||||
background-color: var(--color-justi-modifie);
|
||||
}
|
||||
.invalide {
|
||||
background-color: var(--color-justi-invalide);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
</style>
|
@ -88,11 +88,11 @@ div.submit > input {
|
||||
{{ form.modimpl }}
|
||||
{{ render_field_errors(form, 'modimpl') }}
|
||||
</div>
|
||||
{# Raison #}
|
||||
{# Description #}
|
||||
<div>
|
||||
<div>{{ form.assi_raison.label }}</div>
|
||||
{{ form.assi_raison() }}
|
||||
{{ render_field_errors(form, 'assi_raison') }}
|
||||
<div>{{ form.description.label }}</div>
|
||||
{{ form.description() }}
|
||||
{{ render_field_errors(form, 'description') }}
|
||||
</div>
|
||||
{# Date dépot #}
|
||||
{{ form.entry_date.label }} : {{ form.entry_date }}
|
||||
|
@ -52,8 +52,8 @@
|
||||
|
||||
<div class="assi-row">
|
||||
<div class="assi-label">
|
||||
<legend for="assi_raison">Raison</legend>
|
||||
<textarea name="assi_raison" id="assi_raison" cols="75" rows="4" maxlength="500"></textarea>
|
||||
<legend for="raison">Raison</legend>
|
||||
<textarea name="raison" id="raison" cols="75" rows="4" maxlength="500"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -135,7 +135,7 @@
|
||||
const { deb, fin } = getDates()
|
||||
|
||||
const etat = field.querySelector('#assi_etat').value;
|
||||
const raison = field.querySelector('#assi_raison').value;
|
||||
const raison = field.querySelector('#raison').value;
|
||||
const module = field.querySelector("#ajout_assiduite_module_impl").value;
|
||||
|
||||
return {
|
||||
@ -168,7 +168,7 @@
|
||||
field.querySelector('#assi_date_debut').value = "";
|
||||
field.querySelector('#assi_date_fin').value = "";
|
||||
field.querySelector('#assi_etat').value = "attente";
|
||||
field.querySelector('#assi_raison').value = "";
|
||||
field.querySelector('#raison').value = "";
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
{# Formulaire ajout ou modification de justificatif
|
||||
Si justif, edit #}
|
||||
{% extends "sco_page.j2" %}
|
||||
{% import 'wtf.j2' as wtf %}
|
||||
|
||||
@ -16,6 +18,16 @@ form#ajout-justificatif-etud {
|
||||
form#ajout-justificatif-etud > div {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
div.fichiers {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
div.fichiers ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
span.suppr_fichier_just {
|
||||
margin-right: 8px;
|
||||
}
|
||||
div.submit {
|
||||
margin-top: 12px;
|
||||
}
|
||||
@ -61,15 +73,33 @@ div.submit > input {
|
||||
</div>
|
||||
{# Raison #}
|
||||
<div>
|
||||
<div>{{ form.assi_raison.label }}</div>
|
||||
{{ form.assi_raison() }}
|
||||
{{ render_field_errors(form, 'assi_raison') }}
|
||||
<div>{{ form.raison.label }}</div>
|
||||
{{ form.raison() }}
|
||||
{{ render_field_errors(form, 'raison') }}
|
||||
</div>
|
||||
{# Fichier(s) justificatif(s) #}
|
||||
<div>
|
||||
<div>{{ form.fichiers.label }}</div>
|
||||
{{ form.fichiers() }}
|
||||
{{ render_field_errors(form, 'fichiers') }}
|
||||
<div class="fichiers">
|
||||
{# Liste des fichiers existants #}
|
||||
{% if justif and nb_files > 0 %}
|
||||
<div><b>{{nb_files}} fichiers justificatifs déposés
|
||||
{% if filenames|length < nb_files %}
|
||||
, dont {{filenames|length}} vous sont accessibles
|
||||
{% endif %}
|
||||
</b>
|
||||
</div>
|
||||
<ul>
|
||||
{% for filename in filenames %}
|
||||
<li><span data-justif_id="{{justif.id}}" class="suppr_fichier_just"
|
||||
>{{scu.icontag("delete_img", alt="supprimer", title="Supprimer")|safe}}</span>
|
||||
{{filename}}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{# Ajout fichier(s) justificatif(s) #}
|
||||
<div>
|
||||
<div>{{ form.fichiers.label }}</div>
|
||||
{{ form.fichiers() }}
|
||||
{{ render_field_errors(form, 'fichiers') }}
|
||||
</div>
|
||||
</div>
|
||||
{# Date dépot #}
|
||||
{{ form.entry_date.label }} : {{ form.entry_date }}
|
||||
@ -83,12 +113,15 @@ div.submit > input {
|
||||
</fieldset>
|
||||
</form>
|
||||
</section>
|
||||
{% if tableau %}
|
||||
<section class="assi-liste">
|
||||
{{tableau | safe }}
|
||||
</section>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% include "assiduites/explication_etats_justifs.j2" %}
|
||||
|
||||
{% endblock app_content %}
|
||||
|
||||
{% block scripts %}
|
||||
@ -108,4 +141,54 @@ $('.timepicker').timepicker({
|
||||
scrollbar: false
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
// Suppression d'un fichier justificatif
|
||||
function delete_file(justif_id, fileName, liElement) {
|
||||
// Construct the URL
|
||||
var url = "{{url_for('apiweb.justif_remove', justif_id=-1, scodoc_dept=g.scodoc_dept)}}".replace('-1', justif_id);
|
||||
|
||||
payload = {
|
||||
"remove": "list",
|
||||
"filenames" : [ fileName ],
|
||||
}
|
||||
// Send API request
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
// Hide the <li> element on successful deletion
|
||||
liElement.style.display = 'none';
|
||||
sco_message("fichier supprimé");
|
||||
} else {
|
||||
// Handle non-successful responses here
|
||||
console.error('Deletion failed:', response.statusText);
|
||||
sco_error_message("erreur lors de la suppression du fichier");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
sco_error_message("erreur lors de la suppression du fichier (2)");
|
||||
});
|
||||
}
|
||||
|
||||
// Add event listeners to all elements with class 'suppr_fichier_just'
|
||||
var deleteButtons = document.querySelectorAll('.suppr_fichier_just');
|
||||
deleteButtons.forEach(function(button) {
|
||||
button.addEventListener('click', function() {
|
||||
// Get the text content of the next sibling node
|
||||
var justif_id = this.dataset.justif_id;
|
||||
var fileName = this.nextSibling.nodeValue.trim();
|
||||
var liElement = this.parentNode; // Get the parent <li> element
|
||||
delete_file(justif_id, fileName, liElement);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock scripts %}
|
||||
|
@ -169,7 +169,7 @@
|
||||
right: 0;
|
||||
background-color: var(--color-justi-invalide) !important;
|
||||
}
|
||||
.color.attente::before {
|
||||
.color.attente::before, .color.modifie::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 25%;
|
||||
@ -475,6 +475,10 @@
|
||||
let est_just = ""
|
||||
if (dayJustificatifs.some((j) => j.etat.toLowerCase() === "valide")) {
|
||||
est_just = "est_just";
|
||||
} else if (dayJustificatifs.some((j) => j.etat.toLowerCase() === "attente")) {
|
||||
est_just = "attente";
|
||||
} else if (dayJustificatifs.some((j) => j.etat.toLowerCase() === "modifie")) {
|
||||
est_just = "modifie";
|
||||
} else if (dayJustificatifs.some((j) => j.etat.toLowerCase() !== "valide")) {
|
||||
est_just = "invalide";
|
||||
}
|
||||
@ -535,6 +539,8 @@
|
||||
est_just = ["est_just"];
|
||||
} else if (justificatifsMatin.some((j) => j.etat.toLowerCase() === "attente")) {
|
||||
est_just = ["attente"];
|
||||
} else if (justificatifsMatin.some((j) => j.etat.toLowerCase() === "modifie")) {
|
||||
est_just = ["modifie"];
|
||||
}
|
||||
else if (justificatifsMatin.some((j) => j.etat.toLowerCase() !== "valide")) {
|
||||
est_just = ["invalide"];
|
||||
@ -579,8 +585,9 @@
|
||||
est_just = ["est_just"];
|
||||
} else if (justificatifsAprem.some((j) => j.etat.toLowerCase() === "attente")) {
|
||||
est_just = ["attente"];
|
||||
}
|
||||
else if (justificatifsAprem.some((j) => j.etat.toLowerCase() !== "valide")) {
|
||||
} else if (justificatifsAprem.some((j) => j.etat.toLowerCase() === "modifie")) {
|
||||
est_just = ["modifie"];
|
||||
} else if (justificatifsAprem.some((j) => j.etat.toLowerCase() !== "valide")) {
|
||||
est_just = ["invalide"];
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,10 @@ affectent notamment les comptages d'absences de tous les bulletins des
|
||||
</div>
|
||||
<div class="row">
|
||||
<h1>Emplois du temps</h1>
|
||||
<div class="help">ScoDoc peut récupérer les emplois du temps de chaque session.</div>
|
||||
<div class="help">ScoDoc peut récupérer les emplois du temps de chaque session.
|
||||
Voir <a href="https://scodoc.org/EmploisDuTemps" class="stdlink"
|
||||
target="_blank">la documentation</a>.
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="config-edt">
|
||||
{{ wtf.form_field(form.edt_ics_path) }}
|
||||
|
@ -4,4 +4,7 @@
|
||||
<h2>Liste de l'assiduité et des justificatifs de {{sco.etud.html_link_fiche()|safe}}</h2>
|
||||
{{tableau | safe }}
|
||||
</div>
|
||||
|
||||
{% include "assiduites/explication_etats_justifs.j2" %}
|
||||
|
||||
{% endblock app_content %}
|
||||
|
@ -16,6 +16,12 @@
|
||||
|
||||
{{ form_groups_choice|safe }}
|
||||
|
||||
<form id="show_modules_titles_form" method="GET">
|
||||
<input type="checkbox" name="show_modules_titles" {{
|
||||
'checked' if show_modules_titles else ''}}
|
||||
onchange="this.form.submit()"/> noms complets des modules</input>
|
||||
</form>
|
||||
|
||||
<div>
|
||||
<span id="menu-navi">
|
||||
<button type="button" class="btn btn-default btn-sm move-today"
|
||||
@ -38,9 +44,16 @@
|
||||
</li>
|
||||
<li>Si vous filtrez par groupe, les évènements dont le groupe n'est pas reconnu seront affichés.
|
||||
</li>
|
||||
{% if formsemestre.can_be_edited_by(current_user) %}
|
||||
<li><a class="stdlink" href="{{
|
||||
url_for('notes.formsemestre_edt_help_config',
|
||||
scodoc_dept=g.scodoc_dept, formsemestre_id= formsemestre.id)
|
||||
}}">Aide à la configuration de l'emploi du temps</a>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock app_content %}
|
||||
|
||||
{% block scripts %}
|
||||
@ -107,7 +120,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
const calendar = new Calendar(container, options);
|
||||
|
||||
fetch(`${SCO_URL}/../api/formsemestre/{{formsemestre.id}}/edt?{{groups_query_args|safe}}`)
|
||||
fetch(`${SCO_URL}/../api/formsemestre/{{formsemestre.id}}/edt?{{groups_query_args|safe}}&show_modules_titles={{show_modules_titles}}`)
|
||||
.then(r=>{return r.json()})
|
||||
.then(events=>{
|
||||
if (typeof events == 'string') {
|
||||
|
87
app/templates/formsemestre/edt_help_config.j2
Normal file
87
app/templates/formsemestre/edt_help_config.j2
Normal file
@ -0,0 +1,87 @@
|
||||
{% extends "sco_page.j2" %}
|
||||
|
||||
{% block app_content %}
|
||||
<style>
|
||||
table#edt2group {
|
||||
border-collapse: collapse;
|
||||
margin: 25px 0;
|
||||
font-size: 0.9em;
|
||||
font-family: sans-serif;
|
||||
min-width: 400px;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
table#edt2group thead tr th {
|
||||
background-color: #009879;
|
||||
color: #ffffff;
|
||||
text-align: left;
|
||||
}
|
||||
table#edt2group thead tr th,
|
||||
table#edt2group tbody tr td {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
table#edt2group tbody tr {
|
||||
border-bottom: 1px solid #dddddd !important;
|
||||
}
|
||||
|
||||
table#edt2group tbody tr:nth-of-type(even) {
|
||||
background-color: #f3f3f3 !important;
|
||||
}
|
||||
|
||||
table#edt2group tbody tr:last-of-type {
|
||||
border-bottom: 2px solid #009879 !important;
|
||||
}
|
||||
table#edt2group tbody tr.active-row {
|
||||
font-weight: bold !important;
|
||||
color: #009879 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="tab-content">
|
||||
<h2>Aide à la configuration de l'emploi du temps</h2>
|
||||
|
||||
<ul>
|
||||
<li>Nombre d'évènements dans le calendrier ics de ce semestre: {{events_sco|length}}</li>
|
||||
</ul>
|
||||
<h3>Identifiants de groupes trouvés dans ce calendrier</h3>
|
||||
<div class="help">
|
||||
si vous voyez ici de nombreuses lignes, il est possible que l'expression régulière
|
||||
d'extraction soit incorrecte (voir configuration globale) ou bien que votre logiciel d'emploi du temps génère de nombreux évènements non associés à un groupe donné.
|
||||
</div>
|
||||
<div>Voici ce qui a été extrait de l'emploi du temps par l'expression régulière configurée:
|
||||
</div>
|
||||
<ul>
|
||||
{% for gr in edt_groups_ids %}
|
||||
<li>{{ gr }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h3>Table de correspondance entre groupes EDT et groupes ScoDoc</h3>
|
||||
<div class="help">
|
||||
Si votre logiciel d'emploi du temps utilise des identifiants de groupes différents de ceux de ScoDoc, il faut l'indiquer
|
||||
{% if formsemestre.can_change_groups(current_user) %}
|
||||
<a class="stdlink" href="{{ url_for( 'scolar.partition_editor',
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre.id,
|
||||
edit_partition=1 ) }}
|
||||
">dans l'éditeur de partitions</a>
|
||||
{% else %}
|
||||
dans l'éditeur de partitions (vous n'avez pas l'autorisation de le faire vous même).
|
||||
{% endif %}
|
||||
</div>
|
||||
<table id="edt2group">
|
||||
<thead>
|
||||
<tr><th>Groupe EDT</th><th>Groupe ScoDoc</th><th>group_id</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for edt_gr in edt2group %}
|
||||
<tr><td>{{edt_gr or "*"}}</td>
|
||||
<td>{{edt2group[edt_gr].group_name or "tous"}}</td>
|
||||
<td>{{edt2group[edt_gr].id}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock app_content %}
|
@ -400,7 +400,7 @@ def _get_dates_from_assi_form(
|
||||
dt_entry_date = (
|
||||
datetime.datetime.strptime(form.entry_date.data, "%d/%m/%Y")
|
||||
if form.entry_date.data
|
||||
else None
|
||||
else datetime.datetime.now() # local tz
|
||||
)
|
||||
except ValueError:
|
||||
dt_entry_date = None
|
||||
@ -464,7 +464,7 @@ def _record_assiduite_etud(
|
||||
dt_debut_tz_server,
|
||||
dt_fin_tz_server,
|
||||
scu.EtatAssiduite.get(form.assi_etat.data),
|
||||
description=form.assi_raison.data,
|
||||
description=form.description.data,
|
||||
entry_date=dt_entry_date_tz_server,
|
||||
external_data=external_data,
|
||||
moduleimpl=moduleimpl,
|
||||
@ -596,6 +596,64 @@ def bilan_etud():
|
||||
).build()
|
||||
|
||||
|
||||
@bp.route("/edit_justificatif_etud/<int:justif_id>", methods=["GET", "POST"])
|
||||
@scodoc
|
||||
@permission_required(Permission.AbsChange)
|
||||
def edit_justificatif_etud(justif_id: int):
|
||||
"""
|
||||
Edition d'un justificatif
|
||||
Args:
|
||||
justif_id (int): l'identifiant du justificatif
|
||||
|
||||
Returns:
|
||||
str: l'html généré
|
||||
"""
|
||||
justif = Justificatif.get_justificatif(justif_id)
|
||||
form = AjoutJustificatifEtudForm(obj=justif)
|
||||
# Set the default value for the etat field
|
||||
if request.method == "GET":
|
||||
form.date_debut.data = justif.date_debut.strftime("%d/%m/%Y")
|
||||
form.date_fin.data = justif.date_fin.strftime("%d/%m/%Y")
|
||||
if form.date_fin.data == form.date_debut.data:
|
||||
# un seul jour: pas de date de fin, indique les heures
|
||||
form.date_fin.data = ""
|
||||
form.heure_debut.data = justif.date_debut.strftime("%H:%M")
|
||||
form.heure_fin.data = justif.date_fin.strftime("%H:%M")
|
||||
form.entry_date.data = (
|
||||
justif.entry_date.strftime("%d/%m/%Y") if justif.entry_date else ""
|
||||
)
|
||||
form.etat.data = str(justif.etat)
|
||||
|
||||
redirect_url = url_for(
|
||||
"assiduites.liste_assiduites_etud",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
etudid=justif.etudiant.id,
|
||||
)
|
||||
if form.validate_on_submit():
|
||||
if _record_justificatif_etud(justif.etudiant, form, justif):
|
||||
return redirect(redirect_url)
|
||||
|
||||
# Fichiers
|
||||
filenames, nb_files = justif.get_fichiers()
|
||||
|
||||
return render_template(
|
||||
"assiduites/pages/ajout_justificatif_etud.j2",
|
||||
assi_limit_annee=sco_preferences.get_preference(
|
||||
"assi_limit_annee",
|
||||
dept_id=g.scodoc_dept_id,
|
||||
),
|
||||
etud=justif.etudiant,
|
||||
filenames=filenames,
|
||||
form=form,
|
||||
justif=justif,
|
||||
nb_files=nb_files,
|
||||
page_title="Modification justificatif",
|
||||
redirect_url=redirect_url,
|
||||
sco=ScoData(justif.etudiant),
|
||||
scu=scu,
|
||||
)
|
||||
|
||||
|
||||
@bp.route(
|
||||
"/ajout_justificatif_etud", methods=["GET", "POST"]
|
||||
) # was AjoutJustificatifEtud
|
||||
@ -603,7 +661,7 @@ def bilan_etud():
|
||||
@permission_required(Permission.AbsChange)
|
||||
def ajout_justificatif_etud():
|
||||
"""
|
||||
ajout_justificatif_etud : Affichage et création/modification des justificatifs de l'étudiant
|
||||
ajout_justificatif_etud : Affichage et création des justificatifs de l'étudiant
|
||||
Args:
|
||||
etudid (int): l'identifiant de l'étudiant
|
||||
|
||||
@ -654,8 +712,7 @@ def ajout_justificatif_etud():
|
||||
|
||||
|
||||
def _record_justificatif_etud(
|
||||
etud: Identite,
|
||||
form: AjoutJustificatifEtudForm,
|
||||
etud: Identite, form: AjoutJustificatifEtudForm, justif: Justificatif | None = None
|
||||
) -> bool:
|
||||
"""Enregistre les données du formulaire de saisie justificatif (et ses fichiers).
|
||||
Returns ok if successfully recorded, else put error info in the form.
|
||||
@ -663,6 +720,7 @@ def _record_justificatif_etud(
|
||||
form.assi_etat.data : 'absent'
|
||||
form.date_debut.data : '05/12/2023'
|
||||
form.heure_debut.data : '09:06' (heure locale du serveur)
|
||||
Si justif, modifie le justif existant, sinon en crée un nouveau
|
||||
"""
|
||||
(
|
||||
ok,
|
||||
@ -672,30 +730,53 @@ def _record_justificatif_etud(
|
||||
) = _get_dates_from_assi_form(form)
|
||||
|
||||
if not ok:
|
||||
log("_record_justificatif_etud: dates invalides")
|
||||
form.set_error("Erreur: dates invalides")
|
||||
return False
|
||||
etat = scu.EtatJustificatif.get(form.etat.data)
|
||||
if not form.etat.data:
|
||||
log("_record_justificatif_etud: etat invalide")
|
||||
form.set_error("Erreur: état invalide")
|
||||
return False
|
||||
etat = int(form.etat.data)
|
||||
if not scu.EtatJustificatif.is_valid_etat(etat):
|
||||
log(f"_record_justificatif_etud: etat invalide ({etat})")
|
||||
form.set_error("Erreur: état invalide")
|
||||
return False
|
||||
|
||||
try:
|
||||
just = Justificatif.create_justificatif(
|
||||
etud,
|
||||
dt_debut_tz_server,
|
||||
dt_fin_tz_server,
|
||||
etat=etat,
|
||||
raison=form.assi_raison.data,
|
||||
entry_date=dt_entry_date_tz_server,
|
||||
user_id=current_user.id,
|
||||
)
|
||||
db.session.add(just)
|
||||
if not _upload_justificatif_files(just, form):
|
||||
message = ""
|
||||
if justif:
|
||||
form.date_debut.data = dt_debut_tz_server
|
||||
form.date_fin.data = dt_fin_tz_server
|
||||
form.entry_date.data = dt_entry_date_tz_server
|
||||
if justif.edit_from_form(form):
|
||||
message = "Justificatif modifié"
|
||||
else:
|
||||
message = "Pas de modification"
|
||||
else:
|
||||
justif = Justificatif.create_justificatif(
|
||||
etud,
|
||||
dt_debut_tz_server,
|
||||
dt_fin_tz_server,
|
||||
etat=etat,
|
||||
raison=form.raison.data,
|
||||
entry_date=dt_entry_date_tz_server,
|
||||
user_id=current_user.id,
|
||||
)
|
||||
message = "Justificatif créé"
|
||||
db.session.add(justif)
|
||||
if not _upload_justificatif_files(justif, form):
|
||||
flash("Erreur enregistrement fichiers")
|
||||
log("problem in _upload_justificatif_files, rolling back")
|
||||
db.session.rollback()
|
||||
return False
|
||||
db.session.commit()
|
||||
compute_assiduites_justified(etud.id, [just])
|
||||
scass.simple_invalidate_cache(just.to_dict(), etud.id)
|
||||
flash("Justificatif enregistré")
|
||||
compute_assiduites_justified(etud.id, [justif])
|
||||
scass.simple_invalidate_cache(justif.to_dict(), etud.id)
|
||||
flash(message)
|
||||
return True
|
||||
except ScoValueError as exc:
|
||||
log(f"_record_justificatif_etud: erreur {exc.args[0]}")
|
||||
db.session.rollback()
|
||||
form.set_error(f"Erreur: {exc.args[0]}")
|
||||
return False
|
||||
@ -1474,10 +1555,10 @@ def _action_modifier_assiduite(assi: Assiduite):
|
||||
|
||||
|
||||
def _action_modifier_justificatif(justi: Justificatif):
|
||||
"Modifie le justificatif avec les valeurs dans le form"
|
||||
form = request.form
|
||||
|
||||
# Gestion des Dates
|
||||
|
||||
date_debut: datetime = scu.is_iso_formated(form["date_debut"], True)
|
||||
date_fin: datetime = scu.is_iso_formated(form["date_fin"], True)
|
||||
if date_debut is None or date_fin is None or date_fin < date_debut:
|
||||
@ -1556,40 +1637,30 @@ def _preparer_objet(
|
||||
_preparer_objet("justificatif", justi, sans_gros_objet=True)
|
||||
)
|
||||
|
||||
else:
|
||||
else: # objet == "justificatif"
|
||||
justif: Justificatif = objet
|
||||
objet_prepare["etat"] = (
|
||||
scu.EtatJustificatif(objet.etat).version_lisible().capitalize()
|
||||
scu.EtatJustificatif(justif.etat).version_lisible().capitalize()
|
||||
)
|
||||
objet_prepare["real_etat"] = scu.EtatJustificatif(objet.etat).name.lower()
|
||||
objet_prepare["raison"] = "" if objet.raison is None else objet.raison
|
||||
objet_prepare["real_etat"] = scu.EtatJustificatif(justif.etat).name.lower()
|
||||
objet_prepare["raison"] = "" if justif.raison is None else justif.raison
|
||||
objet_prepare["raison"] = objet_prepare["raison"].strip()
|
||||
|
||||
objet_prepare["justification"] = {"assiduites": [], "fichiers": {}}
|
||||
if not sans_gros_objet:
|
||||
assiduites: list[int] = scass.justifies(objet)
|
||||
assiduites: list[int] = scass.justifies(justif)
|
||||
for assi_id in assiduites:
|
||||
assi: Assiduite = Assiduite.query.get(assi_id)
|
||||
objet_prepare["justification"]["assiduites"].append(
|
||||
_preparer_objet("assiduite", assi, sans_gros_objet=True)
|
||||
)
|
||||
|
||||
# Récupération de l'archive avec l'archiver
|
||||
archive_name: str = objet.fichier
|
||||
filenames: list[str] = []
|
||||
archiver: JustificatifArchiver = JustificatifArchiver()
|
||||
if archive_name is not None:
|
||||
filenames = archiver.list_justificatifs(archive_name, objet.etudiant)
|
||||
# fichiers justificatifs archivés:
|
||||
filenames, nb_files = justif.get_fichiers()
|
||||
objet_prepare["justification"]["fichiers"] = {
|
||||
"total": len(filenames),
|
||||
"filenames": [],
|
||||
"total": nb_files,
|
||||
"filenames": filenames,
|
||||
}
|
||||
for filename in filenames:
|
||||
if int(filename[1]) == current_user.id or current_user.has_permission(
|
||||
Permission.AbsJustifView
|
||||
):
|
||||
objet_prepare["justification"]["fichiers"]["filenames"].append(
|
||||
filename[0]
|
||||
)
|
||||
|
||||
objet_prepare["date_fin"] = objet.date_fin.strftime("%d/%m/%y à %H:%M")
|
||||
objet_prepare["real_date_fin"] = objet.date_fin.isoformat()
|
||||
@ -1600,7 +1671,7 @@ def _preparer_objet(
|
||||
|
||||
objet_prepare["etud_nom"] = objet.etudiant.nomprenom
|
||||
|
||||
if objet.user_id != None:
|
||||
if objet.user_id is not None:
|
||||
user: User = User.query.get(objet.user_id)
|
||||
objet_prepare["saisie_par"] = user.get_nomprenom()
|
||||
else:
|
||||
|
@ -103,7 +103,7 @@ from app.scodoc import html_sco_header
|
||||
from app.pe import pe_view
|
||||
from app.scodoc import sco_apogee_compare
|
||||
from app.scodoc import sco_archives
|
||||
from app.scodoc import sco_archive_formsemestre
|
||||
from app.scodoc import sco_archives_formsemestre
|
||||
from app.scodoc import sco_assiduites
|
||||
from app.scodoc import sco_bulletins
|
||||
from app.scodoc import sco_bulletins_pdf
|
||||
@ -2973,24 +2973,24 @@ sco_publish(
|
||||
)
|
||||
sco_publish(
|
||||
"/formsemestre_archive",
|
||||
sco_archive_formsemestre.formsemestre_archive,
|
||||
sco_archives_formsemestre.formsemestre_archive,
|
||||
Permission.ScoView,
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
sco_publish(
|
||||
"/formsemestre_delete_archive",
|
||||
sco_archive_formsemestre.formsemestre_delete_archive,
|
||||
sco_archives_formsemestre.formsemestre_delete_archive,
|
||||
Permission.ScoView,
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
sco_publish(
|
||||
"/formsemestre_list_archives",
|
||||
sco_archive_formsemestre.formsemestre_list_archives,
|
||||
sco_archives_formsemestre.formsemestre_list_archives,
|
||||
Permission.ScoView,
|
||||
)
|
||||
sco_publish(
|
||||
"/formsemestre_get_archived_file",
|
||||
sco_archive_formsemestre.formsemestre_get_archived_file,
|
||||
sco_archives_formsemestre.formsemestre_get_archived_file,
|
||||
Permission.ScoView,
|
||||
)
|
||||
sco_publish("/view_apo_csv", sco_etape_apogee_view.view_apo_csv, Permission.EditApogee)
|
||||
|
@ -39,9 +39,14 @@ from app.decorators import (
|
||||
)
|
||||
from app.forms.formsemestre import change_formation, edit_modimpls_codes_apo
|
||||
from app.models import Formation, FormSemestre, ScoDocSiteConfig
|
||||
from app.scodoc import sco_formations, sco_formation_versions
|
||||
from app.scodoc import sco_groups_view
|
||||
from app.scodoc import (
|
||||
sco_edt_cal,
|
||||
sco_formations,
|
||||
sco_formation_versions,
|
||||
sco_groups_view,
|
||||
)
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from app.scodoc import sco_utils as scu
|
||||
from app.views import notes_bp as bp
|
||||
from app.views import ScoData
|
||||
|
||||
@ -158,6 +163,7 @@ def formsemestre_edit_modimpls_codes(formsemestre_id: int):
|
||||
@permission_required(Permission.ScoView)
|
||||
def formsemestre_edt(formsemestre_id: int):
|
||||
"""Expérimental: affiche emploi du temps du semestre"""
|
||||
show_modules_titles = scu.to_bool(request.args.get("show_modules_titles", False))
|
||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||
cfg = ScoDocSiteConfig.query.filter_by(name="assi_morning_time").first()
|
||||
hour_start = cfg.value.split(":")[0].lstrip(" 0") if cfg else "7"
|
||||
@ -182,4 +188,25 @@ def formsemestre_edt(formsemestre_id: int):
|
||||
),
|
||||
groups_query_args=groups_infos.groups_query_args,
|
||||
sco=ScoData(formsemestre=formsemestre),
|
||||
show_modules_titles=show_modules_titles,
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/formsemestre/edt_help_config/<int:formsemestre_id>")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
def formsemestre_edt_help_config(formsemestre_id: int):
|
||||
"""Page d'aide à la configuration de l'extraction emplois du temps
|
||||
Affiche les identifiants extraits de l'ics et ceux de ScoDoc.
|
||||
"""
|
||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||
edt2group = sco_edt_cal.formsemestre_retreive_groups_from_edt_id(formsemestre)
|
||||
events_sco, edt_groups_ids = sco_edt_cal.load_and_convert_ics(formsemestre)
|
||||
return render_template(
|
||||
"formsemestre/edt_help_config.j2",
|
||||
formsemestre=formsemestre,
|
||||
edt2group=edt2group,
|
||||
edt_groups_ids=edt_groups_ids,
|
||||
events_sco=events_sco,
|
||||
sco=ScoData(formsemestre=formsemestre),
|
||||
)
|
||||
|
@ -10,7 +10,7 @@ from tests.unit import yaml_setup, call_view
|
||||
import app
|
||||
from app.models import Formation, FormSemestre
|
||||
from app.scodoc import (
|
||||
sco_archive_formsemestre,
|
||||
sco_archives_formsemestre,
|
||||
sco_cost_formation,
|
||||
sco_debouche,
|
||||
sco_edit_ue,
|
||||
@ -182,8 +182,8 @@ def test_formsemestre_misc_views(test_client):
|
||||
assert isinstance(ans, Response)
|
||||
assert ans.status == "200 OK"
|
||||
assert ans.mimetype == scu.JSON_MIMETYPE
|
||||
ans = sco_archive_formsemestre.formsemestre_archive(formsemestre.id)
|
||||
ans = sco_archive_formsemestre.formsemestre_list_archives(formsemestre.id)
|
||||
ans = sco_archives_formsemestre.formsemestre_archive(formsemestre.id)
|
||||
ans = sco_archives_formsemestre.formsemestre_list_archives(formsemestre.id)
|
||||
|
||||
# ----- MENU STATISTIQUES
|
||||
ans = sco_report.formsemestre_report_counts(formsemestre.id)
|
||||
|
Loading…
Reference in New Issue
Block a user