forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -646,8 +646,8 @@ def justif_import(justif_id: int = None):
|
|||||||
return json_error(404, err.args[0])
|
return json_error(404, err.args[0])
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/justificatif/<int:justif_id>/export/<filename>", methods=["POST"])
|
@bp.route("/justificatif/<int:justif_id>/export/<filename>", methods=["GET", "POST"])
|
||||||
@api_web_bp.route("/justificatif/<int:justif_id>/export/<filename>", methods=["POST"])
|
@api_web_bp.route("/justificatif/<int:justif_id>/export/<filename>", methods=["GET", "POST"])
|
||||||
@scodoc
|
@scodoc
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required(Permission.AbsChange)
|
@permission_required(Permission.AbsChange)
|
||||||
|
@ -204,6 +204,40 @@ class Assiduite(db.Model):
|
|||||||
sco_abs_notification.abs_notify(etud.id, nouv_assiduite.date_debut)
|
sco_abs_notification.abs_notify(etud.id, nouv_assiduite.date_debut)
|
||||||
return nouv_assiduite
|
return nouv_assiduite
|
||||||
|
|
||||||
|
def set_moduleimpl(self, moduleimpl_id: int | str) -> bool:
|
||||||
|
moduleimpl: ModuleImpl = ModuleImpl.query.get(moduleimpl_id)
|
||||||
|
if moduleimpl is not None:
|
||||||
|
# Vérification de l'inscription de l'étudiant
|
||||||
|
if moduleimpl.est_inscrit(self.etudiant):
|
||||||
|
self.moduleimpl_id = moduleimpl.id
|
||||||
|
else:
|
||||||
|
raise ScoValueError("L'étudiant n'est pas inscrit au module")
|
||||||
|
elif isinstance(moduleimpl_id, str):
|
||||||
|
if self.external_data is None:
|
||||||
|
self.external_data = {"module": moduleimpl_id}
|
||||||
|
else:
|
||||||
|
self.external_data["module"] = moduleimpl_id
|
||||||
|
self.moduleimpl_id = None
|
||||||
|
else:
|
||||||
|
# Vérification si module forcé
|
||||||
|
formsemestre: FormSemestre = get_formsemestre_from_data(
|
||||||
|
{
|
||||||
|
"etudid": self.etudid,
|
||||||
|
"date_debut": self.date_debut,
|
||||||
|
"date_fin": self.date_fin,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
force: bool
|
||||||
|
|
||||||
|
if formsemestre:
|
||||||
|
force = is_assiduites_module_forced(formsemestre_id=formsemestre.id)
|
||||||
|
else:
|
||||||
|
force = is_assiduites_module_forced(dept_id=etud.dept_id)
|
||||||
|
|
||||||
|
if force:
|
||||||
|
raise ScoValueError("Module non renseigné")
|
||||||
|
return True
|
||||||
|
|
||||||
def supprimer(self):
|
def supprimer(self):
|
||||||
from app.scodoc import sco_assiduites as scass
|
from app.scodoc import sco_assiduites as scass
|
||||||
|
|
||||||
|
@ -481,7 +481,7 @@ class ScoDocDateTimePicker extends HTMLElement {
|
|||||||
} else {
|
} else {
|
||||||
// Mettre à jour la valeur de l'input caché avant la soumission
|
// Mettre à jour la valeur de l'input caché avant la soumission
|
||||||
this.hiddenInput.value = this.isValid()
|
this.hiddenInput.value = this.isValid()
|
||||||
? this.valueAsDate.toIsoUtcString()
|
? this.valueAsDate.toFakeIso()
|
||||||
: "";
|
: "";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -17,6 +17,7 @@ class ListeAssiJusti(tb.Table):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
NB_PAR_PAGE: int = 25
|
NB_PAR_PAGE: int = 25
|
||||||
|
MAX_PAR_PAGE: int = 200
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -221,7 +222,7 @@ class RowAssiJusti(tb.Row):
|
|||||||
# Ajout de l'étudiant
|
# Ajout de l'étudiant
|
||||||
self.table: ListeAssiJusti
|
self.table: ListeAssiJusti
|
||||||
if self.table.options.show_etu:
|
if self.table.options.show_etu:
|
||||||
self._etud()
|
self._etud(lien_redirection)
|
||||||
|
|
||||||
# Type d'objet
|
# Type d'objet
|
||||||
self._type()
|
self._type()
|
||||||
@ -287,7 +288,7 @@ class RowAssiJusti(tb.Row):
|
|||||||
|
|
||||||
self.add_cell("obj_type", "Type", obj_type)
|
self.add_cell("obj_type", "Type", obj_type)
|
||||||
|
|
||||||
def _etud(self) -> None:
|
def _etud(self, lien_redirection) -> None:
|
||||||
etud = self.etud
|
etud = self.etud
|
||||||
self.table.group_titles.update(
|
self.table.group_titles.update(
|
||||||
{
|
{
|
||||||
@ -357,7 +358,7 @@ class RowAssiJusti(tb.Row):
|
|||||||
obj_id=self.ligne["obj_id"],
|
obj_id=self.ligne["obj_id"],
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
)
|
)
|
||||||
html.append(f'<a href="{url}">Détails</a>') # utiliser url_for
|
html.append(f'<a title="Détails" href="{url}">ℹ️</a>') # utiliser url_for
|
||||||
|
|
||||||
# Modifier
|
# Modifier
|
||||||
url = url_for(
|
url = url_for(
|
||||||
@ -367,7 +368,7 @@ class RowAssiJusti(tb.Row):
|
|||||||
obj_id=self.ligne["obj_id"],
|
obj_id=self.ligne["obj_id"],
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
)
|
)
|
||||||
html.append(f'<a href="{url}">Modifier</a>') # utiliser url_for
|
html.append(f'<a title="Modifier" href="{url}">📝</a>') # utiliser url_for
|
||||||
|
|
||||||
# Supprimer
|
# Supprimer
|
||||||
url = url_for(
|
url = url_for(
|
||||||
@ -377,11 +378,9 @@ class RowAssiJusti(tb.Row):
|
|||||||
obj_id=self.ligne["obj_id"],
|
obj_id=self.ligne["obj_id"],
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
)
|
)
|
||||||
html.append(f'<a href="{url}">Supprimer</a>') # utiliser url_for
|
html.append(f'<a title="Supprimer" href="{url}">❌</a>') # utiliser url_for
|
||||||
|
|
||||||
self.add_cell(
|
self.add_cell("actions", "Actions", " ".join(html), no_excel=True)
|
||||||
"actions", "Actions", " ".join(html), raw_content="test", no_excel=True
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Filtre:
|
class Filtre:
|
||||||
@ -492,6 +491,8 @@ class Options:
|
|||||||
):
|
):
|
||||||
self.page: int = page
|
self.page: int = page
|
||||||
self.nb_ligne_page: int = nb_ligne_page
|
self.nb_ligne_page: int = nb_ligne_page
|
||||||
|
if self.nb_ligne_page is not None:
|
||||||
|
self.nb_ligne_page = min(nb_ligne_page, ListeAssiJusti.MAX_PAR_PAGE)
|
||||||
|
|
||||||
self.show_pres: bool = show_pres in Options.VRAI
|
self.show_pres: bool = show_pres in Options.VRAI
|
||||||
self.show_reta: bool = show_reta in Options.VRAI
|
self.show_reta: bool = show_reta in Options.VRAI
|
||||||
@ -503,9 +504,13 @@ class Options:
|
|||||||
def remplacer(self, **kwargs):
|
def remplacer(self, **kwargs):
|
||||||
for k, v in kwargs.items():
|
for k, v in kwargs.items():
|
||||||
if k.startswith("show_"):
|
if k.startswith("show_"):
|
||||||
self.__setattr__(k, v in Options.VRAI)
|
setattr(self, k, v in Options.VRAI)
|
||||||
elif k in ["page", "nb_ligne_page"]:
|
elif k in ["page", "nb_ligne_page"]:
|
||||||
self.__setattr__(k, int(v))
|
setattr(self, k, int(v))
|
||||||
|
if k == "nb_ligne_page":
|
||||||
|
self.nb_ligne_page = min(
|
||||||
|
self.nb_ligne_page, ListeAssiJusti.MAX_PAR_PAGE
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Data:
|
class Data:
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
{% block pageContent %}
|
{% block pageContent %}
|
||||||
<div class="pageContent">
|
<div class="pageContent">
|
||||||
<h3>Justifier des absences ou retards</h3>
|
<h3>Justifier des absences ou retards</h3>
|
||||||
{% include "assiduites/widgets/tableau_base.j2" %}
|
|
||||||
|
|
||||||
|
|
||||||
<section class="justi-form page">
|
<section class="justi-form page">
|
||||||
|
|
||||||
@ -58,28 +56,9 @@
|
|||||||
|
|
||||||
</section>
|
</section>
|
||||||
<section class="liste">
|
<section class="liste">
|
||||||
<a class="icon filter" onclick="filterJusti()"></a>
|
{{tableau | safe }}
|
||||||
{% include "assiduites/widgets/tableau_justi.j2" %}
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="legende">
|
|
||||||
|
|
||||||
<h3>Gestion des justificatifs</h3>
|
|
||||||
<p>
|
|
||||||
Faites
|
|
||||||
<span style="font-style: italic;">clic droit</span> sur une ligne du tableau pour afficher le menu
|
|
||||||
contextuel :
|
|
||||||
<ul>
|
|
||||||
<li>Détails : Affiche les détails du justificatif sélectionné</li>
|
|
||||||
<li>Editer : Permet de modifier le justificatif (dates, etat, ajouter/supprimer fichier etc)</li>
|
|
||||||
<li>Supprimer : Permet de supprimer le justificatif (Action Irréversible)</li>
|
|
||||||
</ul>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Cliquer sur l'icone d'entonoir afin de filtrer le tableau des justificatifs</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -167,17 +146,15 @@
|
|||||||
processData: false,
|
processData: false,
|
||||||
success: () => {
|
success: () => {
|
||||||
pushToast(generateToast(document.createTextNode(`Importation du fichier : ${f.name} finie`)));
|
pushToast(generateToast(document.createTextNode(`Importation du fichier : ${f.name} finie`)));
|
||||||
loadAll();
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
if (in_files.files.length == 0) {
|
$.when(...requests).done(() => {
|
||||||
loadAll();
|
location.reload();
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function validerFormulaire(btn) {
|
function validerFormulaire(btn) {
|
||||||
@ -258,7 +235,6 @@
|
|||||||
const assi_evening = '{{assi_evening}}';
|
const assi_evening = '{{assi_evening}}';
|
||||||
|
|
||||||
window.onload = () => {
|
window.onload = () => {
|
||||||
loadAll();
|
|
||||||
document.getElementById('justi_journee').addEventListener('click', () => { dayOnly() });
|
document.getElementById('justi_journee').addEventListener('click', () => { dayOnly() });
|
||||||
dayOnly()
|
dayOnly()
|
||||||
|
|
||||||
|
@ -2,95 +2,6 @@
|
|||||||
<div class="pageContent">
|
<div class="pageContent">
|
||||||
|
|
||||||
<h2>Liste de l'assiduité et des justificatifs de <span class="rouge">{{sco.etud.nomprenom}}</span></h2>
|
<h2>Liste de l'assiduité et des justificatifs de <span class="rouge">{{sco.etud.nomprenom}}</span></h2>
|
||||||
{% include "assiduites/widgets/tableau_base.j2" %}
|
{{tableau | safe }}
|
||||||
<h3>Assiduité :</h3>
|
|
||||||
<span class="iconline">
|
|
||||||
<a class="icon filter" onclick="filterAssi()"></a>
|
|
||||||
<a class="icon download" onclick="downloadAssi()"></a>
|
|
||||||
</span>
|
|
||||||
{% include "assiduites/widgets/tableau_assi.j2" %}
|
|
||||||
<h3>Justificatifs :</h3>
|
|
||||||
<span class="iconline">
|
|
||||||
<a class="icon filter" onclick="filterJusti()"></a>
|
|
||||||
<a class="icon download" onclick="downloadJusti()"></a>
|
|
||||||
</span>
|
|
||||||
{% include "assiduites/widgets/tableau_justi.j2" %}
|
|
||||||
<ul id="contextMenu" class="context-menu">
|
|
||||||
<li id="detailOption">Detail</li>
|
|
||||||
<li id="editOption">Editer</li>
|
|
||||||
<li id="deleteOption">Supprimer</li>
|
|
||||||
</ul>
|
|
||||||
<div class="legende">
|
|
||||||
<h3>Gestion des justificatifs</h3>
|
|
||||||
<p>
|
|
||||||
Faites
|
|
||||||
<span style="font-style: italic;">clic droit</span> sur une ligne du tableau pour afficher le menu
|
|
||||||
contextuel :
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>Détails : Affiche les détails du justificatif sélectionné</li>
|
|
||||||
<li>Editer : Permet de modifier le justificatif (dates, etat, ajouter/supprimer fichier etc)</li>
|
|
||||||
<li>Supprimer : Permet de supprimer le justificatif (Action Irréversible)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>Vous pouvez filtrer le tableau en cliquant sur l'icone d'entonnoir sous le titre du tableau.</p>
|
|
||||||
|
|
||||||
<h3>Gestion de l'assiduité</h3>
|
|
||||||
<p>
|
|
||||||
Faites
|
|
||||||
<span style="font-style: italic;">clic droit</span> sur une ligne du tableau pour afficher le menu
|
|
||||||
contextuel :
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>Détails : affiche les détails de l'assiduité sélectionnée</li>
|
|
||||||
<li>Éditer : modifier l'élément (module, état)</li>
|
|
||||||
<li>Supprimer : supprimer l'élément (action irréversible)</li>
|
|
||||||
</ul>
|
|
||||||
<p>Vous pouvez filtrer le tableau en cliquant sur l'icone d'entonnoir sous le titre du tableau.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock app_content %}
|
{% endblock app_content %}
|
||||||
|
|
||||||
<script>
|
|
||||||
const etudid = {{ sco.etud.id }}
|
|
||||||
|
|
||||||
const assiduite_unique_id = {{ assi_id }};
|
|
||||||
|
|
||||||
const assi_limit_annee = "{{ assi_limit_annee }}" == "True" ? true : false;
|
|
||||||
|
|
||||||
|
|
||||||
function wayForFilter() {
|
|
||||||
if (typeof assiduites[etudid] !== "undefined") {
|
|
||||||
console.log("Done")
|
|
||||||
let assiduite = assiduites[etudid].filter((a) => { return a.assiduite_id == assiduite_unique_id });
|
|
||||||
|
|
||||||
if (assiduite) {
|
|
||||||
assiduite = assiduite[0]
|
|
||||||
filterAssiduites["filters"] = {
|
|
||||||
"obj_id": [
|
|
||||||
assiduite.assiduite_id,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
const obj_ids = assiduite.justificatifs ? assiduite.justificatifs.map((j) => { return j.justif_id }) : []
|
|
||||||
filterJustificatifs["filters"] = {
|
|
||||||
"obj_id": obj_ids
|
|
||||||
}
|
|
||||||
|
|
||||||
loadAll();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setTimeout(wayForFilter, 250)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onload = () => {
|
|
||||||
loadAll();
|
|
||||||
|
|
||||||
if (assiduite_unique_id != -1) {
|
|
||||||
wayForFilter()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
@ -2,6 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<h3>Options</h3>
|
<h3>Options</h3>
|
||||||
<div id="options-tableau">
|
<div id="options-tableau">
|
||||||
|
{% if afficher_options != false %}
|
||||||
<label for="show_pres">afficher les présences</label>
|
<label for="show_pres">afficher les présences</label>
|
||||||
{% if options.show_pres %}
|
{% if options.show_pres %}
|
||||||
<input type="checkbox" id="show_pres" name="show_pres" checked>
|
<input type="checkbox" id="show_pres" name="show_pres" checked>
|
||||||
@ -22,7 +23,7 @@
|
|||||||
<input type="checkbox" id="show_desc" name="show_desc">
|
<input type="checkbox" id="show_desc" name="show_desc">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<br>
|
<br>
|
||||||
|
{% endif %}
|
||||||
<label for="nb_ligne_page">Nombre de ligne par page : </label>
|
<label for="nb_ligne_page">Nombre de ligne par page : </label>
|
||||||
<input type="number" name="nb_ligne_page" id="nb_ligne_page" value="{{options.nb_ligne_page}}">
|
<input type="number" name="nb_ligne_page" id="nb_ligne_page" value="{{options.nb_ligne_page}}">
|
||||||
|
|
||||||
@ -38,6 +39,8 @@
|
|||||||
</select>
|
</select>
|
||||||
<br>
|
<br>
|
||||||
<button onclick="updateTableau()">valider</button>
|
<button onclick="updateTableau()">valider</button>
|
||||||
|
<a style="margin-left:32px;" href="{{request.url}}&fmt=xlsx">{{scu.ICON_XLS|safe}}</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -62,6 +65,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.small-font {
|
.small-font {
|
||||||
font-size: 9pt;
|
font-size: 9pt;
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
<div>
|
<div>
|
||||||
{% for assi in objet.justification.assiduites %}
|
{% for assi in objet.justification.assiduites %}
|
||||||
<a href="{{url_for('assiduites.tableau_assiduite_actions', type='assiduite', action='details', obj_id=assi.assiduite_id, scodoc_dept=g.scodoc_dept)}}"
|
<a href="{{url_for('assiduites.tableau_assiduite_actions', type='assiduite', action='details', obj_id=assi.assiduite_id, scodoc_dept=g.scodoc_dept)}}"
|
||||||
target="_blank" rel="noopener noreferrer">Assiduité {{assi.etat}} du {{assi.date_debut}} au
|
target="_blank">Assiduité {{assi.etat}} du {{assi.date_debut}} au
|
||||||
{{assi.date_fin}}</a>
|
{{assi.date_fin}}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
@ -88,14 +88,13 @@
|
|||||||
<span class="info-label">Fichiers enregistrés: </span>
|
<span class="info-label">Fichiers enregistrés: </span>
|
||||||
{% if objet.justification.fichiers.total != 0 %}
|
{% if objet.justification.fichiers.total != 0 %}
|
||||||
<div>Total : {{objet.justification.fichiers.total}} </div>
|
<div>Total : {{objet.justification.fichiers.total}} </div>
|
||||||
<div>
|
<ul>
|
||||||
{% for filename in objet.justification.fichiers.filenames %}
|
{% for filename in objet.justification.fichiers.filenames %}
|
||||||
<form method="post"
|
<li><a
|
||||||
action="{{url_for('api.justif_export',justif_id=objet.justif_id,filename=filename, scodoc_dept=g.scodoc_dept)}}">
|
href="{{url_for('api.justif_export',justif_id=objet.justif_id,filename=filename, scodoc_dept=g.scodoc_dept)}}">{{filename}}</a>
|
||||||
<button type="submit">{{filename}}</button>
|
</li>
|
||||||
</form>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</ul>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="text">Aucun</span>
|
<span class="text">Aucun</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
<h1>Modifier {{type}} </h1>
|
<h1>Modifier {{type}} </h1>
|
||||||
|
|
||||||
<form action="" method="post">
|
<form action="" method="post" enctype="multipart/form-data">
|
||||||
<input type="hidden" name="obj_id" value="{{obj_id}}">
|
<input type="hidden" name="obj_id" value="{{obj_id}}">
|
||||||
|
<input type="hidden" name="table_url" id="table_url" value="">
|
||||||
|
|
||||||
{% if type == "Assiduité" %}
|
{% if type == "Assiduité" %}
|
||||||
<input type="hidden" name="obj_type" value="assiduite">
|
<input type="hidden" name="obj_type" value="assiduite">
|
||||||
@ -18,8 +19,6 @@
|
|||||||
<legend for="description">Description</legend>
|
<legend for="description">Description</legend>
|
||||||
<textarea name="description" id="description" cols="50" rows="5">{{objet.description}}</textarea>
|
<textarea name="description" id="description" cols="50" rows="5">{{objet.description}}</textarea>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<input type="hidden" name="obj_type" value="justificatif">
|
<input type="hidden" name="obj_type" value="justificatif">
|
||||||
|
|
||||||
@ -47,21 +46,11 @@
|
|||||||
<div>Total : {{objet.justification.fichiers.total}} </div>
|
<div>Total : {{objet.justification.fichiers.total}} </div>
|
||||||
<ul>
|
<ul>
|
||||||
{% for filename in objet.justification.fichiers.filenames %}
|
{% for filename in objet.justification.fichiers.filenames %}
|
||||||
<li>
|
<li data-id="{{filename}}">
|
||||||
<script id="replace">
|
<a data-file="{{filename}}">❌</a>
|
||||||
link = document.createElement('a');
|
<a data-link=""
|
||||||
link.textContent = "{{filename}}";
|
href="{{url_for('api.justif_export',justif_id=objet.justif_id,filename=filename, scodoc_dept=g.scodoc_dept)}}"><span
|
||||||
url = "{{url_for('api.justif_export',justif_id=objet.justif_id,filename=filename, scodoc_dept=g.scodoc_dept)}}";
|
data-file="{{filename}}">{{filename}}</span></a>
|
||||||
link.addEventListener('click', () => { downloadFile(url) });
|
|
||||||
document.getElementById('replace').replaceWith(link);
|
|
||||||
</script>
|
|
||||||
<script id="replace2">
|
|
||||||
link = document.createElement('a');
|
|
||||||
link.textContent = "Supprimer";
|
|
||||||
link.setAttribute('data-file', "{{filename}}");
|
|
||||||
link.addEventListener('click', () => { removeFile(link) });
|
|
||||||
document.getElementById('replace2').replaceWith(link);
|
|
||||||
</script>
|
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
@ -82,26 +71,37 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
function removeFile(element) {
|
function removeFile(element) {
|
||||||
element.toggleAttribute("data-remove")
|
const link = document.querySelector(`*[data-id="${element.getAttribute('data-file')}"] a[data-link] span`);
|
||||||
}
|
link?.toggleAttribute("data-remove")
|
||||||
|
|
||||||
function downloadFile(url) {
|
|
||||||
console.warn(url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteFiles(justif_id) {
|
function deleteFiles(justif_id) {
|
||||||
|
|
||||||
const filenames = Array.from(document.querySelectorAll("*[data-remove]")).map((el) => el.getAttribute("data-file"))
|
const filenames = Array.from(document.querySelectorAll("*[data-remove]")).map((el) => el.getAttribute("data-file"))
|
||||||
|
|
||||||
obj = {
|
obj = {
|
||||||
"remove": "list",
|
"remove": "list",
|
||||||
"filenames": filenames
|
"filenames": filenames
|
||||||
}
|
}
|
||||||
|
//faire un POST à l'api justificatifs
|
||||||
console.warn(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
document.getElementById('etat').value = "{{objet.real_etat}}";
|
document.getElementById('etat').value = "{{objet.real_etat}}";
|
||||||
|
document.getElementById('table_url').value = document.referrer;
|
||||||
|
document.querySelectorAll("a[data-file]").forEach((e) => {
|
||||||
|
e.addEventListener('click', () => {
|
||||||
|
removeFile(e);
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
<style>
|
||||||
|
[data-remove] {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-file] {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
@ -266,13 +266,6 @@ def signal_assiduites_etud():
|
|||||||
if etud.dept_id != g.scodoc_dept_id:
|
if etud.dept_id != g.scodoc_dept_id:
|
||||||
abort(404, "étudiant inexistant dans ce département")
|
abort(404, "étudiant inexistant dans ce département")
|
||||||
|
|
||||||
# Récupération de la date (par défaut la date du jour)
|
|
||||||
date = request.args.get("date", datetime.date.today().isoformat())
|
|
||||||
heures: list[str] = [
|
|
||||||
request.args.get("heure_deb", ""),
|
|
||||||
request.args.get("heure_fin", ""),
|
|
||||||
]
|
|
||||||
|
|
||||||
# gestion évaluations (Appel à la page depuis les évaluations)
|
# gestion évaluations (Appel à la page depuis les évaluations)
|
||||||
|
|
||||||
saisie_eval: bool = request.args.get("saisie_eval") is not None
|
saisie_eval: bool = request.args.get("saisie_eval") is not None
|
||||||
@ -305,26 +298,13 @@ def signal_assiduites_etud():
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Gestion des horaires (journée, matin, soir)
|
|
||||||
|
|
||||||
morning = ScoDocSiteConfig.assi_get_rounded_time("assi_morning_time", "08:00:00")
|
|
||||||
lunch = ScoDocSiteConfig.assi_get_rounded_time("assi_lunch_time", "13:00:00")
|
|
||||||
afternoon = ScoDocSiteConfig.assi_get_rounded_time(
|
|
||||||
"assi_afternoon_time", "18:00:00"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Gestion du selecteur de moduleimpl (pour le tableau différé)
|
|
||||||
select = f"""
|
|
||||||
<select class="dynaSelect">
|
|
||||||
{render_template("assiduites/widgets/simplemoduleimpl_select.j2")}
|
|
||||||
</select>
|
|
||||||
"""
|
|
||||||
|
|
||||||
tableau = _preparer_tableau(
|
tableau = _preparer_tableau(
|
||||||
|
liste_assi.Data.from_etudiants(
|
||||||
etud,
|
etud,
|
||||||
|
),
|
||||||
filename=f"assiduite-{etudid}",
|
filename=f"assiduite-{etudid}",
|
||||||
afficher_etu=False,
|
afficher_etu=False,
|
||||||
filtre=liste_assi.Filtre(type_obj=0),
|
filtre=liste_assi.Filtre(type_obj=1),
|
||||||
options=liste_assi.Options(show_module=True),
|
options=liste_assi.Options(show_module=True),
|
||||||
)
|
)
|
||||||
if not tableau[0]:
|
if not tableau[0]:
|
||||||
@ -393,7 +373,7 @@ def liste_assiduites_etud():
|
|||||||
if etud.dept_id != g.scodoc_dept_id:
|
if etud.dept_id != g.scodoc_dept_id:
|
||||||
abort(404, "étudiant inexistant dans ce département")
|
abort(404, "étudiant inexistant dans ce département")
|
||||||
|
|
||||||
# Gestion d'une assiduité unique (redirigé depuis le calendrier)
|
# Gestion d'une assiduité unique (redirigé depuis le calendrier) TODO-Assiduites
|
||||||
assiduite_id: int = request.args.get("assiduite_id", -1)
|
assiduite_id: int = request.args.get("assiduite_id", -1)
|
||||||
|
|
||||||
# Préparation de la page
|
# Préparation de la page
|
||||||
@ -409,18 +389,25 @@ def liste_assiduites_etud():
|
|||||||
"css/assiduites.css",
|
"css/assiduites.css",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
tableau = _preparer_tableau(
|
||||||
|
liste_assi.Data.from_etudiants(
|
||||||
|
etud,
|
||||||
|
),
|
||||||
|
filename=f"assiduites-justificatifs-{etudid}",
|
||||||
|
afficher_etu=False,
|
||||||
|
filtre=liste_assi.Filtre(type_obj=0),
|
||||||
|
options=liste_assi.Options(show_module=True),
|
||||||
|
)
|
||||||
|
if not tableau[0]:
|
||||||
|
return tableau[1]
|
||||||
# Peuplement du template jinja
|
# Peuplement du template jinja
|
||||||
return HTMLBuilder(
|
return HTMLBuilder(
|
||||||
header,
|
header,
|
||||||
render_template(
|
render_template(
|
||||||
"assiduites/pages/liste_assiduites.j2",
|
"assiduites/pages/liste_assiduites.j2",
|
||||||
sco=ScoData(etud),
|
sco=ScoData(etud),
|
||||||
date=datetime.date.today().isoformat(),
|
|
||||||
assi_id=assiduite_id,
|
assi_id=assiduite_id,
|
||||||
assi_limit_annee=sco_preferences.get_preference(
|
tableau=tableau[1],
|
||||||
"assi_limit_annee",
|
|
||||||
dept_id=g.scodoc_dept_id,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
).build()
|
).build()
|
||||||
|
|
||||||
@ -517,6 +504,19 @@ def ajout_justificatif_etud():
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tableau = _preparer_tableau(
|
||||||
|
liste_assi.Data.from_etudiants(
|
||||||
|
etud,
|
||||||
|
),
|
||||||
|
filename=f"justificatifs-{etudid}",
|
||||||
|
afficher_etu=False,
|
||||||
|
filtre=liste_assi.Filtre(type_obj=2),
|
||||||
|
options=liste_assi.Options(show_module=False, show_desc=True),
|
||||||
|
afficher_options=False,
|
||||||
|
)
|
||||||
|
if not tableau[0]:
|
||||||
|
return tableau[1]
|
||||||
|
|
||||||
# Peuplement du template jinja
|
# Peuplement du template jinja
|
||||||
return HTMLBuilder(
|
return HTMLBuilder(
|
||||||
header,
|
header,
|
||||||
@ -529,6 +529,7 @@ def ajout_justificatif_etud():
|
|||||||
),
|
),
|
||||||
assi_morning=ScoDocSiteConfig.get("assi_morning_time", "08:00"),
|
assi_morning=ScoDocSiteConfig.get("assi_morning_time", "08:00"),
|
||||||
assi_evening=ScoDocSiteConfig.get("assi_afternoon_time", "18:00"),
|
assi_evening=ScoDocSiteConfig.get("assi_afternoon_time", "18:00"),
|
||||||
|
tableau=tableau[1],
|
||||||
),
|
),
|
||||||
).build()
|
).build()
|
||||||
|
|
||||||
@ -1061,11 +1062,12 @@ def visu_assi_group():
|
|||||||
|
|
||||||
|
|
||||||
def _preparer_tableau(
|
def _preparer_tableau(
|
||||||
*etudiants: Identite,
|
data: liste_assi.Data,
|
||||||
filename: str = "tableau-assiduites",
|
filename: str = "tableau-assiduites",
|
||||||
afficher_etu: bool = True,
|
afficher_etu: bool = True,
|
||||||
filtre: liste_assi.Filtre = None,
|
filtre: liste_assi.Filtre = None,
|
||||||
options: liste_assi.Options = None,
|
options: liste_assi.Options = None,
|
||||||
|
afficher_options: bool = True,
|
||||||
) -> tuple[bool, "Response"]:
|
) -> tuple[bool, "Response"]:
|
||||||
"""
|
"""
|
||||||
_preparer_tableau prépare un tableau d'assiduités / justificatifs
|
_preparer_tableau prépare un tableau d'assiduités / justificatifs
|
||||||
@ -1120,7 +1122,7 @@ def _preparer_tableau(
|
|||||||
)
|
)
|
||||||
|
|
||||||
table: liste_assi.ListeAssiJusti = liste_assi.ListeAssiJusti(
|
table: liste_assi.ListeAssiJusti = liste_assi.ListeAssiJusti(
|
||||||
table_data=liste_assi.Data.from_etudiants(*etudiants),
|
table_data=data,
|
||||||
options=options,
|
options=options,
|
||||||
filtre=filtre,
|
filtre=filtre,
|
||||||
)
|
)
|
||||||
@ -1138,6 +1140,7 @@ def _preparer_tableau(
|
|||||||
tableau=table.html(),
|
tableau=table.html(),
|
||||||
total_pages=table.total_pages,
|
total_pages=table.total_pages,
|
||||||
options=options,
|
options=options,
|
||||||
|
afficher_options=afficher_options,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -1186,6 +1189,100 @@ def tableau_assiduite_actions():
|
|||||||
obj_id=obj_id,
|
obj_id=obj_id,
|
||||||
moduleimpl=module,
|
moduleimpl=module,
|
||||||
)
|
)
|
||||||
|
# Cas des POSTS
|
||||||
|
if obj_type == "assiduite":
|
||||||
|
try:
|
||||||
|
_action_modifier_assiduite(objet)
|
||||||
|
except ScoValueError as error:
|
||||||
|
raise ScoValueError(error.args[0], request.referrer) from error
|
||||||
|
flash("L'assiduité a bien été modifiée.")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
_action_modifier_justificatif(objet)
|
||||||
|
except ScoValueError as error:
|
||||||
|
raise ScoValueError(error.args[0], request.referrer) from error
|
||||||
|
flash("Le justificatif a bien été modifié.")
|
||||||
|
return redirect(request.form["table_url"])
|
||||||
|
|
||||||
|
|
||||||
|
def _action_modifier_assiduite(assi: Assiduite):
|
||||||
|
form = request.form
|
||||||
|
|
||||||
|
# Gestion de l'état
|
||||||
|
etat = scu.EtatAssiduite.get(form["etat"])
|
||||||
|
if etat is not None:
|
||||||
|
assi.etat = etat
|
||||||
|
if etat == scu.EtatAssiduite.PRESENT:
|
||||||
|
assi.est_just = False
|
||||||
|
else:
|
||||||
|
assi.est_just = len(get_assiduites_justif(assi.assiduite_id, False)) > 0
|
||||||
|
|
||||||
|
# Gestion de la description
|
||||||
|
assi.description = form["description"]
|
||||||
|
|
||||||
|
module: str = form["moduleimpl_select"]
|
||||||
|
|
||||||
|
if module == "":
|
||||||
|
module = None
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
module = int(module)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
assi.set_moduleimpl(module)
|
||||||
|
|
||||||
|
db.session.add(assi)
|
||||||
|
db.session.commit()
|
||||||
|
scass.simple_invalidate_cache(assi.to_dict(True), assi.etudid)
|
||||||
|
|
||||||
|
|
||||||
|
def _action_modifier_justificatif(justi: Justificatif):
|
||||||
|
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:
|
||||||
|
raise ScoValueError("Dates invalides", request.referrer)
|
||||||
|
justi.date_debut = date_debut
|
||||||
|
justi.date_fin = date_fin
|
||||||
|
|
||||||
|
# Gestion de l'état
|
||||||
|
etat = scu.EtatJustificatif.get(form["etat"])
|
||||||
|
if etat is not None:
|
||||||
|
justi.etat = etat
|
||||||
|
else:
|
||||||
|
raise ScoValueError("État invalide", request.referrer)
|
||||||
|
|
||||||
|
# Gestion de la raison
|
||||||
|
justi.raison = form["raison"]
|
||||||
|
|
||||||
|
# Gestion des fichiers
|
||||||
|
files = request.files.getlist("justi_fich")
|
||||||
|
if len(files) != 0:
|
||||||
|
files = request.files.values()
|
||||||
|
|
||||||
|
archive_name: str = justi.fichier
|
||||||
|
# Utilisation de l'archiver de justificatifs
|
||||||
|
archiver: JustificatifArchiver = JustificatifArchiver()
|
||||||
|
|
||||||
|
for fich in files:
|
||||||
|
archive_name, _ = archiver.save_justificatif(
|
||||||
|
justi.etudiant,
|
||||||
|
filename=fich.filename,
|
||||||
|
data=fich.stream.read(),
|
||||||
|
archive_name=archive_name,
|
||||||
|
user_id=current_user.id,
|
||||||
|
)
|
||||||
|
|
||||||
|
justi.fichier = archive_name
|
||||||
|
|
||||||
|
db.session.add(justi)
|
||||||
|
db.session.commit()
|
||||||
|
scass.compute_assiduites_justified(justi.etudid, reset=True)
|
||||||
|
scass.simple_invalidate_cache(justi.to_dict(True), justi.etudid)
|
||||||
|
|
||||||
|
|
||||||
def _preparer_objet(
|
def _preparer_objet(
|
||||||
|
Loading…
Reference in New Issue
Block a user