From 2b04c952c48ad1d3cd840a61274ee02698ca83da Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Fri, 22 Dec 2023 15:31:30 +0100 Subject: [PATCH] Formulaire edit_justificatif_etud + diverses correctifs mineurs --- app/scodoc/sco_assiduites.py | 2 +- app/tables/liste_assiduites.py | 27 ++- .../assiduites/pages/ajout_assiduite_etud.j2 | 6 +- .../assiduites/pages/ajout_assiduites.j2 | 8 +- .../pages/ajout_justificatif_etud.j2 | 79 ++++++++- app/views/assiduites.py | 155 +++++++++++++----- 6 files changed, 213 insertions(+), 64 deletions(-) diff --git a/app/scodoc/sco_assiduites.py b/app/scodoc/sco_assiduites.py index 1bedcdb59..97f7f2de9 100644 --- a/app/scodoc/sco_assiduites.py +++ b/app/scodoc/sco_assiduites.py @@ -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, diff --git a/app/tables/liste_assiduites.py b/app/tables/liste_assiduites.py index e39e9813d..b9d031b12 100644 --- a/app/tables/liste_assiduites.py +++ b/app/tables/liste_assiduites.py @@ -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'ℹ️') # 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'📝') # Supprimer diff --git a/app/templates/assiduites/pages/ajout_assiduite_etud.j2 b/app/templates/assiduites/pages/ajout_assiduite_etud.j2 index 711ae5f26..5d5e5d5d0 100644 --- a/app/templates/assiduites/pages/ajout_assiduite_etud.j2 +++ b/app/templates/assiduites/pages/ajout_assiduite_etud.j2 @@ -90,9 +90,9 @@ div.submit > input { {# Raison #}
-
{{ form.assi_raison.label }}
- {{ form.assi_raison() }} - {{ render_field_errors(form, 'assi_raison') }} +
{{ form.raison.label }}
+ {{ form.raison() }} + {{ render_field_errors(form, 'raison') }}
{# Date dépot #} {{ form.entry_date.label }} : {{ form.entry_date }} diff --git a/app/templates/assiduites/pages/ajout_assiduites.j2 b/app/templates/assiduites/pages/ajout_assiduites.j2 index ca65d0329..9326d9307 100644 --- a/app/templates/assiduites/pages/ajout_assiduites.j2 +++ b/app/templates/assiduites/pages/ajout_assiduites.j2 @@ -52,8 +52,8 @@
- Raison - + Raison +
@@ -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 = ""; } diff --git a/app/templates/assiduites/pages/ajout_justificatif_etud.j2 b/app/templates/assiduites/pages/ajout_justificatif_etud.j2 index 4d28e6287..bd4abe925 100644 --- a/app/templates/assiduites/pages/ajout_justificatif_etud.j2 +++ b/app/templates/assiduites/pages/ajout_justificatif_etud.j2 @@ -1,3 +1,5 @@ +{# Formulaire ajout ou modification de justificatif +Si justif, edit #} {% extends "sco_page.j2" %} {% import 'wtf.j2' as wtf %} @@ -61,11 +63,27 @@ div.submit > input { {# Raison #}
-
{{ form.assi_raison.label }}
- {{ form.assi_raison() }} - {{ render_field_errors(form, 'assi_raison') }} +
{{ form.raison.label }}
+ {{ form.raison() }} + {{ render_field_errors(form, 'raison') }}
- {# Fichier(s) justificatif(s) #} + {# Liste des fichiers existants #} + {% if justif and nb_files > 0 %} +
+
{{nb_files}} fichiers justificatifs déposés + {% if filenames|length < nb_files %} + , dont {{filenames|length}} vous sont accessibles + {% endif %} +
    + {% for filename in filenames %} +
  • {{scu.icontag("delete_img", alt="supprimer", title="Supprimer")|safe}} + {{filename}}
  • + {% endfor %} +
+
+ {% endif %} + {# Ajout fichier(s) justificatif(s) #}
{{ form.fichiers.label }}
{{ form.fichiers() }} @@ -83,10 +101,11 @@ div.submit > input { + {% if tableau %}
{{tableau | safe }}
- + {% endif %}
{% endblock app_content %} @@ -108,4 +127,54 @@ $('.timepicker').timepicker({ scrollbar: false }); + {% endblock scripts %} diff --git a/app/views/assiduites.py b/app/views/assiduites.py index ee32f3271..b7bc1ad98 100644 --- a/app/views/assiduites.py +++ b/app/views/assiduites.py @@ -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.raison.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/", 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: