forked from ScoDoc/ScoDoc
This commit is contained in:
parent
ffdaf2a19a
commit
db44e8e5f4
@ -62,6 +62,11 @@ class AjoutAssiOrJustForm(FlaskForm):
|
||||
if field:
|
||||
field.errors.append(err_msg)
|
||||
|
||||
def disable_all(self):
|
||||
"Disable all fields"
|
||||
for field in self:
|
||||
field.render_kw = {"disabled": True}
|
||||
|
||||
date_debut = StringField(
|
||||
"Date de début",
|
||||
validators=[validators.Length(max=10)],
|
||||
@ -175,36 +180,3 @@ class AjoutJustificatifEtudForm(AjoutAssiOrJustForm):
|
||||
validators=[DataRequired(message="This field is required.")],
|
||||
)
|
||||
fichiers = MultipleFileField(label="Ajouter des fichiers")
|
||||
|
||||
|
||||
class ChoixDateForm(FlaskForm):
|
||||
"""
|
||||
Formulaire de choix de date
|
||||
(utilisé par la page de choix de date
|
||||
si la date courante n'est pas dans le semestre)
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"Init form, adding a filed for our error messages"
|
||||
super().__init__(*args, **kwargs)
|
||||
self.ok = True
|
||||
self.error_messages: list[str] = [] # used to report our errors
|
||||
|
||||
def set_error(self, err_msg, field=None):
|
||||
"Set error message both in form and field"
|
||||
self.ok = False
|
||||
self.error_messages.append(err_msg)
|
||||
if field:
|
||||
field.errors.append(err_msg)
|
||||
|
||||
date = StringField(
|
||||
"Date",
|
||||
validators=[validators.Length(max=10)],
|
||||
render_kw={
|
||||
"class": "datepicker",
|
||||
"size": 10,
|
||||
"id": "date",
|
||||
},
|
||||
)
|
||||
submit = SubmitField("Enregistrer")
|
||||
cancel = SubmitField("Annuler", render_kw={"formnovalidate": True})
|
||||
|
58
app/forms/assiduite/edit_assiduite_etud.py
Normal file
58
app/forms/assiduite/edit_assiduite_etud.py
Normal file
@ -0,0 +1,58 @@
|
||||
""" """
|
||||
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import SelectField, RadioField, TextAreaField, validators, SubmitField
|
||||
from app.scodoc.sco_utils import EtatAssiduite
|
||||
|
||||
|
||||
class EditAssiForm(FlaskForm):
|
||||
"""
|
||||
Formulaire de modification d'une assiduité
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"Init form, adding a filed for our error messages"
|
||||
super().__init__(*args, **kwargs)
|
||||
self.ok = True
|
||||
self.error_messages: list[str] = [] # used to report our errors
|
||||
|
||||
def set_error(self, err_msg, field=None):
|
||||
"Set error message both in form and field"
|
||||
self.ok = False
|
||||
self.error_messages.append(err_msg)
|
||||
if field:
|
||||
field.errors.append(err_msg)
|
||||
|
||||
def disable_all(self):
|
||||
"Disable all fields"
|
||||
for field in self:
|
||||
field.render_kw = {"disabled": True}
|
||||
|
||||
assi_etat = RadioField(
|
||||
"État:",
|
||||
choices=[
|
||||
(EtatAssiduite.ABSENT.value, EtatAssiduite.ABSENT.version_lisible()),
|
||||
(EtatAssiduite.RETARD.value, EtatAssiduite.RETARD.version_lisible()),
|
||||
(EtatAssiduite.PRESENT.value, EtatAssiduite.PRESENT.version_lisible()),
|
||||
],
|
||||
default="absent",
|
||||
validators=[
|
||||
validators.DataRequired("spécifiez le type d'évènement à signaler"),
|
||||
],
|
||||
)
|
||||
modimpl = SelectField(
|
||||
"Module",
|
||||
choices={}, # will be populated dynamically
|
||||
)
|
||||
description = TextAreaField(
|
||||
"Description",
|
||||
render_kw={
|
||||
"id": "description",
|
||||
"cols": 75,
|
||||
"rows": 4,
|
||||
"maxlength": 500,
|
||||
},
|
||||
)
|
||||
|
||||
submit = SubmitField("Enregistrer")
|
||||
cancel = SubmitField("Annuler", render_kw={"formnovalidate": True})
|
@ -360,6 +360,16 @@ class Assiduite(ScoDocModel):
|
||||
|
||||
return "Module non spécifié" if traduire else None
|
||||
|
||||
def get_moduleimpl_id(self) -> int | str | None:
|
||||
"""
|
||||
Retourne le ModuleImpl associé à l'assiduité
|
||||
"""
|
||||
if self.moduleimpl_id is not None:
|
||||
return self.moduleimpl_id
|
||||
if self.external_data is not None and "module" in self.external_data:
|
||||
return self.external_data["module"]
|
||||
return None
|
||||
|
||||
def get_saisie(self) -> str:
|
||||
"""
|
||||
retourne le texte "saisie le <date> par <User>"
|
||||
@ -395,6 +405,14 @@ class Assiduite(ScoDocModel):
|
||||
if force:
|
||||
raise ScoValueError("Module non renseigné")
|
||||
|
||||
@classmethod
|
||||
def get_assiduite(cls, assiduite_id: int) -> "Assiduite":
|
||||
"""Assiduité ou 404, cherche uniquement dans le département courant"""
|
||||
query = Assiduite.query.filter_by(id=assiduite_id)
|
||||
if g.scodoc_dept:
|
||||
query = query.join(Identite).filter_by(dept_id=g.scodoc_dept_id)
|
||||
return query.first_or_404()
|
||||
|
||||
|
||||
class Justificatif(ScoDocModel):
|
||||
"""
|
||||
|
@ -870,21 +870,12 @@ function setupAssiduiteBubble(el, assiduite) {
|
||||
const infos = document.createElement("a");
|
||||
infos.className = "";
|
||||
infos.textContent = `ℹ️`;
|
||||
infos.title = "Cliquez pour plus d'informations";
|
||||
infos.title = "Détails / Modifier";
|
||||
infos.target = "_blank";
|
||||
infos.href = `tableau_assiduite_actions?type=assiduite&action=details&obj_id=${assiduite.assiduite_id}`;
|
||||
|
||||
// Ajout d'un lien pour modifier l'assiduité
|
||||
const modifs = document.createElement("a");
|
||||
modifs.className = "";
|
||||
modifs.textContent = `📝`;
|
||||
modifs.title = "Cliquez pour modifier l'assiduité";
|
||||
modifs.target = "_blank";
|
||||
modifs.href = `tableau_assiduite_actions?type=assiduite&action=modifier&obj_id=${assiduite.assiduite_id}`;
|
||||
infos.href = `edit_assiduite_etud/${assiduite.assiduite_id}`;
|
||||
|
||||
const actionsDiv = document.createElement("div");
|
||||
actionsDiv.className = "assiduite-actions";
|
||||
actionsDiv.appendChild(modifs);
|
||||
actionsDiv.appendChild(infos);
|
||||
bubble.appendChild(actionsDiv);
|
||||
|
||||
|
@ -600,33 +600,22 @@ class RowAssiJusti(tb.Row):
|
||||
url: str
|
||||
html: list[str] = []
|
||||
|
||||
# Détails
|
||||
url = url_for(
|
||||
"assiduites.tableau_assiduite_actions",
|
||||
type=self.ligne["type"],
|
||||
action="details",
|
||||
obj_id=self.ligne["obj_id"],
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
html.append(f'<a title="Détails" href="{url}">ℹ️</a>')
|
||||
|
||||
# Modifier
|
||||
if self.ligne["type"] == "justificatif":
|
||||
# Détails/Modifier assiduité
|
||||
url = url_for(
|
||||
"assiduites.edit_justificatif_etud",
|
||||
justif_id=self.ligne["obj_id"],
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
back_url=request.url,
|
||||
)
|
||||
html.append(f'<a title="Détails/Modifier" href="{url}">ℹ️</a>')
|
||||
else:
|
||||
# Détails/Modifier assiduité
|
||||
url = url_for(
|
||||
"assiduites.tableau_assiduite_actions",
|
||||
type=self.ligne["type"],
|
||||
action="modifier",
|
||||
obj_id=self.ligne["obj_id"],
|
||||
"assiduites.edit_assiduite_etud",
|
||||
assiduite_id=self.ligne["obj_id"],
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
html.append(f'<a title="Modifier" href="{url}">📝</a>')
|
||||
html.append(f'<a title="Détails/Modifier" href="{url}">ℹ️</a>')
|
||||
|
||||
# Supprimer
|
||||
url = url_for(
|
||||
|
@ -44,11 +44,33 @@ div.submit > input {
|
||||
</style>
|
||||
<div class="tab-content">
|
||||
<h2>{{title|safe}}</h2>
|
||||
|
||||
{% if readonly %}
|
||||
<h3 class="rouge">Vous n'avez pas la permission de modifier ce justificatif</h3>
|
||||
{% endif %}
|
||||
{% if justif %}
|
||||
<div class="informations">
|
||||
|
||||
<div class="info-saisie">
|
||||
Saisie par {{justif.user.get_prenomnom() if justif.user else "inconnu"}}
|
||||
le {{justif.entry_date.strftime(scu.DATEATIME_FMT) if justif.entry_date else "?"}}
|
||||
<span>Saisie par {{justif.saisie_par}} le {{justif.entry_date}}</span>
|
||||
</div>
|
||||
|
||||
<div class="info-row">
|
||||
<span class="info-label">Assiduités concernées: </span>
|
||||
{% if justif.justification.assiduites %}
|
||||
<ul>
|
||||
{% for assi in justif.justification.assiduites %}
|
||||
<li><a href="{{url_for('assiduites.edit_assiduite_etud',
|
||||
assiduite_id=assi.assiduite_id, scodoc_dept=g.scodoc_dept)
|
||||
}}" target="_blank">{{assi.etat}} du {{assi.date_debut}} au
|
||||
{{assi.date_fin}}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<span class="text">Aucune</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@ -110,7 +132,9 @@ div.submit > input {
|
||||
{% 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>
|
||||
<a href="{{url_for('apiweb.justif_export',justif_id=justif.justif_id,
|
||||
filename=filename, scodoc_dept=g.scodoc_dept)}}">{{filename}}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
@ -126,11 +150,28 @@ div.submit > input {
|
||||
<span class="help" style="margin-left: 12px;">laisser vide pour date courante</span>
|
||||
{{ render_field_errors(form, 'entry_date') }}
|
||||
|
||||
{% if readonly == False %}
|
||||
{# Submit #}
|
||||
<div class="submit">
|
||||
{{ form.submit }} {{ form.cancel }}
|
||||
</div>
|
||||
|
||||
<div class="info-row">
|
||||
<a
|
||||
style="color:red;"
|
||||
href="{{url_for(
|
||||
'assiduites.tableau_assiduite_actions',
|
||||
type='justificatif',
|
||||
action='supprimer',
|
||||
obj_id=justif.justif_id,
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)}}"
|
||||
>Supprimer le justificatif</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
</fieldset>
|
||||
</form>
|
||||
</section>
|
||||
|
@ -242,7 +242,7 @@ Calendrier de l'assiduité
|
||||
document.querySelectorAll('[assi_id]').forEach((el, i) => {
|
||||
el.addEventListener('click', () => {
|
||||
const assi_id = el.getAttribute('assi_id');
|
||||
window.open(`${SCO_URL}Assiduites/tableau_assiduite_actions?type=assiduite&action=details&obj_id=${assi_id}`);
|
||||
window.open(`${SCO_URL}Assiduites/edit_assiduite_etud/${assi_id}`);
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
165
app/templates/assiduites/pages/edit_assiduite_etud.j2
Normal file
165
app/templates/assiduites/pages/edit_assiduite_etud.j2
Normal file
@ -0,0 +1,165 @@
|
||||
{# Ajout d'une "assiduité" sur un étudiant #}
|
||||
|
||||
{% extends "sco_page.j2" %}
|
||||
{% import 'wtf.j2' as wtf %}
|
||||
|
||||
|
||||
{% block styles %}
|
||||
{{super()}}
|
||||
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/assiduites.css">
|
||||
|
||||
<style>
|
||||
.info-row {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
#assi_etat{
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.info-etat {
|
||||
font-size: 110%;
|
||||
font-weight: bold;
|
||||
background-color: rgb(253, 234, 210);
|
||||
border: 1px solid grey;
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.info-saisie {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block app_content %}
|
||||
<div class="tab-content">
|
||||
<h2>Détails Assiduité concernant {{etud.html_link_fiche()|safe}}</h2>
|
||||
|
||||
<div id="informations">
|
||||
<div class="info-saisie">
|
||||
<span>Saisie par {{objet.saisie_par}} le {{objet.entry_date}}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">Période :</span> du <b>{{objet.date_debut}}</b> au <b>{{objet.date_fin}}</b>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">Module :</span> {{objet.module}}
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">État de l'assiduité :</span><span class="info-etat">{{objet.etat}}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">Description:</span>
|
||||
{% if objet.description != "" and objet.description is not None %}
|
||||
<span class="text">{{objet.description}}</span>
|
||||
{% else %}
|
||||
<span class="text fontred">Pas de description</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
{# Affichage des justificatifs si assiduité justifiée #}
|
||||
{% if objet.etat != "Présence" %}
|
||||
<div class="info-row">
|
||||
<span class="info-label">Justifiée: </span>
|
||||
{% if objet.justification.est_just %}
|
||||
<span class="text">Oui</span>
|
||||
{% else %}
|
||||
<span class="text fontred">Non</span>
|
||||
{% if not objet.justification.justificatifs %}
|
||||
<a
|
||||
href="{{url_for(
|
||||
'assiduites.tableau_assiduite_actions',
|
||||
type='assiduite',
|
||||
action='justifier',
|
||||
obj_id=objet.assiduite_id,
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)}}"
|
||||
>Justifier l'assiduité</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="info-row">
|
||||
{% if not objet.justification.justificatifs %}
|
||||
<span class="text info-label">Pas de justificatif associé</span>
|
||||
{% else %}
|
||||
<span class="text info-label">Justificatifs associés:</span>
|
||||
<ul>
|
||||
{% for justi in objet.justification.justificatifs %}
|
||||
<li>
|
||||
<a href="{{url_for('assiduites.edit_justificatif_etud',
|
||||
justif_id=justi.justif_id,scodoc_dept=g.scodoc_dept)}}"
|
||||
target="_blank" rel="noopener noreferrer" style="{{'color:red;' if justi.etat != 'Valide'}}">Justificatif {{justi.etat}} du {{justi.date_debut}} au
|
||||
{{justi.date_fin}}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if readonly != True %}
|
||||
<h2 style="margin-top: 24px;">Modification de l'assiduité</h2>
|
||||
{% for err_msg in form.error_messages %}
|
||||
<div class="wtf-error-messages">
|
||||
{{ err_msg }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<form id="edit-assiduite-form" method="post">
|
||||
{{ form.hidden_tag() }}
|
||||
{# Type d'évènement #}
|
||||
<div class="radio-assi_etat">
|
||||
{{ form.assi_etat.label }}
|
||||
{{ form.assi_etat() }}
|
||||
</div>
|
||||
{# Menu module #}
|
||||
<div class="select-module">
|
||||
{{ form.modimpl.label }} :
|
||||
{{ form.modimpl }}
|
||||
{{ render_field_errors(form, 'modimpl') }}
|
||||
</div>
|
||||
{# Description #}
|
||||
<div>
|
||||
<div>{{ form.description.label }}</div>
|
||||
{{ form.description() }}
|
||||
{{ render_field_errors(form, 'description') }}
|
||||
</div>
|
||||
{# Submit #}
|
||||
<div class="submit info-row">
|
||||
{{ form.submit }} {{ form.cancel }}
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
<div class="info-row">
|
||||
<a
|
||||
style="color:red;"
|
||||
href="{{url_for(
|
||||
'assiduites.tableau_assiduite_actions',
|
||||
type='assiduite',
|
||||
action='supprimer',
|
||||
obj_id=objet.assiduite_id,
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)}}"
|
||||
>Supprimer l'assiduité</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<h3 class="rouge">Vous n'avez pas la permission de modifier cette assiduité</h3>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock app_content %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="{{scu.STATIC_DIR}}/js/etud_info.js"></script>
|
||||
{% include "sco_timepicker.j2" %}
|
||||
{% endblock scripts %}
|
@ -36,6 +36,7 @@ from flask_login import current_user
|
||||
from flask_sqlalchemy.query import Query
|
||||
|
||||
from markupsafe import Markup
|
||||
from werkzeug.exceptions import HTTPException
|
||||
|
||||
from app import db, log
|
||||
from app.comp import res_sem
|
||||
@ -48,8 +49,8 @@ from app.forms.assiduite.ajout_assiduite_etud import (
|
||||
AjoutAssiOrJustForm,
|
||||
AjoutAssiduiteEtudForm,
|
||||
AjoutJustificatifEtudForm,
|
||||
ChoixDateForm,
|
||||
)
|
||||
from app.forms.assiduite.edit_assiduite_etud import EditAssiForm
|
||||
from app.models import (
|
||||
Assiduite,
|
||||
Departement,
|
||||
@ -538,10 +539,8 @@ def _record_assiduite_etud(
|
||||
assi: Assiduite = conflits.first()
|
||||
|
||||
lien: str = url_for(
|
||||
"assiduites.tableau_assiduite_actions",
|
||||
type="assiduite",
|
||||
action="details",
|
||||
obj_id=assi.assiduite_id,
|
||||
"assiduites.edit_assiduite_etud",
|
||||
assiuite_id=assi.assiduite_id,
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
|
||||
@ -612,7 +611,7 @@ def bilan_etud():
|
||||
|
||||
@bp.route("/edit_justificatif_etud/<int:justif_id>", methods=["GET", "POST"])
|
||||
@scodoc
|
||||
@permission_required(Permission.AbsChange)
|
||||
@permission_required(Permission.ScoView)
|
||||
def edit_justificatif_etud(justif_id: int):
|
||||
"""
|
||||
Edition d'un justificatif.
|
||||
@ -624,8 +623,19 @@ def edit_justificatif_etud(justif_id: int):
|
||||
Returns:
|
||||
str: l'html généré
|
||||
"""
|
||||
justif = Justificatif.get_justificatif(justif_id)
|
||||
try:
|
||||
justif = Justificatif.get_justificatif(justif_id)
|
||||
except HTTPException:
|
||||
flash("Justificatif invalide")
|
||||
return redirect(url_for("assiduites.bilan_dept", scodoc_dept=g.scodoc_dept))
|
||||
|
||||
readonly = not current_user.has_permission(Permission.AbsChange)
|
||||
|
||||
form = AjoutJustificatifEtudForm(obj=justif)
|
||||
|
||||
if readonly:
|
||||
form.disable_all()
|
||||
|
||||
# Set the default value for the etat field
|
||||
if request.method == "GET":
|
||||
form.date_debut.data = justif.date_debut.strftime(scu.DATE_FMT)
|
||||
@ -652,7 +662,9 @@ def edit_justificatif_etud(justif_id: int):
|
||||
)
|
||||
|
||||
if form.validate_on_submit():
|
||||
if form.cancel.data: # cancel button
|
||||
if form.cancel.data or not current_user.has_permission(
|
||||
Permission.AbsChange
|
||||
): # cancel button
|
||||
return redirect(redirect_url)
|
||||
if _record_justificatif_etud(justif.etudiant, form, justif):
|
||||
return redirect(redirect_url)
|
||||
@ -667,12 +679,13 @@ def edit_justificatif_etud(justif_id: int):
|
||||
etud=justif.etudiant,
|
||||
filenames=filenames,
|
||||
form=form,
|
||||
justif=justif,
|
||||
justif=_preparer_objet("justificatif", justif),
|
||||
nb_files=nb_files,
|
||||
title=f"Modification justificatif absence de {justif.etudiant.html_link_fiche()}",
|
||||
redirect_url=redirect_url,
|
||||
sco=ScoData(justif.etudiant),
|
||||
scu=scu,
|
||||
readonly=not current_user.has_permission(Permission.AbsChange),
|
||||
)
|
||||
|
||||
|
||||
@ -1672,20 +1685,18 @@ def _preparer_objet(
|
||||
|
||||
# Gestion justification
|
||||
|
||||
if not objet.est_just:
|
||||
objet_prepare["justification"] = {"est_just": False}
|
||||
else:
|
||||
objet_prepare["justification"] = {"est_just": True, "justificatifs": []}
|
||||
objet_prepare["justification"] = {
|
||||
"est_just": objet.est_just,
|
||||
"justificatifs": [],
|
||||
}
|
||||
|
||||
if not sans_gros_objet:
|
||||
justificatifs: list[int] = get_assiduites_justif(
|
||||
objet.assiduite_id, False
|
||||
if not sans_gros_objet:
|
||||
justificatifs: list[int] = get_assiduites_justif(objet.assiduite_id, False)
|
||||
for justi_id in justificatifs:
|
||||
justi: Justificatif = Justificatif.query.get(justi_id)
|
||||
objet_prepare["justification"]["justificatifs"].append(
|
||||
_preparer_objet("justificatif", justi, sans_gros_objet=True)
|
||||
)
|
||||
for justi_id in justificatifs:
|
||||
justi: Justificatif = Justificatif.query.get(justi_id)
|
||||
objet_prepare["justification"]["justificatifs"].append(
|
||||
_preparer_objet("justificatif", justi, sans_gros_objet=True)
|
||||
)
|
||||
|
||||
else: # objet == "justificatif"
|
||||
justif: Justificatif = objet
|
||||
@ -1698,9 +1709,8 @@ def _preparer_objet(
|
||||
|
||||
objet_prepare["justification"] = {"assiduites": [], "fichiers": {}}
|
||||
if not sans_gros_objet:
|
||||
assiduites: list[int] = scass.justifies(justif)
|
||||
for assi_id in assiduites:
|
||||
assi: Assiduite = Assiduite.query.get(assi_id)
|
||||
assiduites: list[Assiduite] = justif.get_assiduites()
|
||||
for assi in assiduites:
|
||||
objet_prepare["justification"]["assiduites"].append(
|
||||
_preparer_objet("assiduite", assi, sans_gros_objet=True)
|
||||
)
|
||||
@ -2152,6 +2162,106 @@ def signal_assiduites_hebdo():
|
||||
)
|
||||
|
||||
|
||||
@bp.route("edit_assiduite_etud/<int:assiduite_id>", methods=["GET", "POST"])
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
def edit_assiduite_etud(assiduite_id: int):
|
||||
"""
|
||||
Page affichant les détails d'une assiduité
|
||||
Si le current_user alors la page propose un formulaire de modification
|
||||
"""
|
||||
try:
|
||||
assi: Assiduite = Assiduite.get_assiduite(assiduite_id=assiduite_id)
|
||||
except HTTPException:
|
||||
flash("Assiduité invalide")
|
||||
return redirect(url_for("assiduites.bilan_dept", scodoc_dept=g.scodoc_dept))
|
||||
|
||||
etud: Identite = assi.etudiant
|
||||
formsemestre: FormSemestre = assi.get_formsemestre()
|
||||
|
||||
readonly: bool = not current_user.has_permission(Permission.AbsChange)
|
||||
|
||||
form: EditAssiForm = EditAssiForm(request.form)
|
||||
if readonly:
|
||||
form.disable_all()
|
||||
|
||||
# peuplement moduleimpl_select
|
||||
modimpls_by_formsemestre = etud.get_modimpls_by_formsemestre(scu.annee_scolaire())
|
||||
choices: OrderedDict = OrderedDict()
|
||||
choices[""] = [("", "Non spécifié"), ("autre", "Autre module (pas dans la liste)")]
|
||||
|
||||
# indique le nom du semestre dans le menu (optgroup)
|
||||
group_name: str = formsemestre.titre_annee()
|
||||
choices[group_name] = [
|
||||
(m.id, f"{m.module.code} {m.module.abbrev or m.module.titre or ''}")
|
||||
for m in modimpls_by_formsemestre[formsemestre.id]
|
||||
if m.module.ue.type == UE_STANDARD
|
||||
]
|
||||
|
||||
choices.move_to_end("", last=False)
|
||||
form.modimpl.choices = choices
|
||||
|
||||
# Vérification formulaire
|
||||
if form.validate_on_submit():
|
||||
if form.cancel.data: # cancel button
|
||||
return redirect(request.referrer)
|
||||
|
||||
# vérification des valeurs
|
||||
|
||||
# Gestion de l'état
|
||||
etat = form.assi_etat.data
|
||||
try:
|
||||
etat = int(etat)
|
||||
etat = scu.EtatAssiduite.inverse().get(etat, None)
|
||||
except ValueError:
|
||||
etat = None
|
||||
|
||||
if etat is None:
|
||||
form.error_messages.append("État invalide")
|
||||
form.ok = False
|
||||
|
||||
description = form.description.data or ""
|
||||
description = description.strip()
|
||||
moduleimpl_id = form.modimpl.data or -1
|
||||
if isinstance(moduleimpl_id, int):
|
||||
try:
|
||||
ModuleImpl.get_moduleimpl(moduleimpl_id)
|
||||
except ValueError:
|
||||
form.error_messages.append("Module invalide")
|
||||
moduleimpl_id = -1
|
||||
form.ok = False
|
||||
|
||||
if form.ok:
|
||||
assi.etat = etat
|
||||
assi.description = description
|
||||
if moduleimpl_id != -1:
|
||||
assi.set_moduleimpl(moduleimpl_id)
|
||||
|
||||
db.session.add(assi)
|
||||
db.session.commit()
|
||||
|
||||
scass.simple_invalidate_cache(assi.to_dict(format_api=True), assi.etudid)
|
||||
|
||||
flash("enregistré")
|
||||
return redirect(request.referrer)
|
||||
|
||||
# Remplissage du formulaire
|
||||
form.assi_etat.data = str(assi.etat)
|
||||
form.description.data = assi.description
|
||||
moduleimpl_id: int | str | None = assi.get_moduleimpl_id() or ""
|
||||
form.modimpl.data = str(moduleimpl_id)
|
||||
|
||||
return render_template(
|
||||
"assiduites/pages/edit_assiduite_etud.j2",
|
||||
etud=etud,
|
||||
sco=ScoData(etud, formsemestre=formsemestre),
|
||||
form=form,
|
||||
readonly=readonly,
|
||||
objet=_preparer_objet("assiduite", assi),
|
||||
title=f"Assiduité {etud.nom_short}",
|
||||
)
|
||||
|
||||
|
||||
def generate_bul_list(etud: Identite, semestre: FormSemestre) -> str:
|
||||
"""Génère la liste des assiduités d'un étudiant pour le bulletin mail"""
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user