diff --git a/app/forms/assiduite/edit_assiduite_etud.py b/app/forms/assiduite/edit_assiduite_etud.py index ca284c01..cdcff62e 100644 --- a/app/forms/assiduite/edit_assiduite_etud.py +++ b/app/forms/assiduite/edit_assiduite_etud.py @@ -1,7 +1,14 @@ """ """ from flask_wtf import FlaskForm -from wtforms import SelectField, RadioField, TextAreaField, validators, SubmitField +from wtforms import ( + StringField, + SelectField, + RadioField, + TextAreaField, + validators, + SubmitField, +) from app.scodoc.sco_utils import EtatAssiduite @@ -53,6 +60,63 @@ class EditAssiForm(FlaskForm): "maxlength": 500, }, ) + date_debut = StringField( + "Date de début", + validators=[validators.Length(max=10)], + render_kw={ + "class": "datepicker", + "size": 10, + "id": "assi_date_debut", + }, + ) + heure_debut = StringField( + "Heure début", + default="", + validators=[validators.Length(max=5)], + render_kw={ + "class": "timepicker", + "size": 5, + "id": "assi_heure_debut", + }, + ) + heure_fin = StringField( + "Heure fin", + default="", + validators=[validators.Length(max=5)], + render_kw={ + "class": "timepicker", + "size": 5, + "id": "assi_heure_fin", + }, + ) + date_fin = StringField( + "Date de fin", + validators=[validators.Length(max=10)], + render_kw={ + "class": "datepicker", + "size": 10, + "id": "assi_date_fin", + }, + ) + entry_date = StringField( + "Date de dépôt ou saisie", + validators=[validators.Length(max=10)], + render_kw={ + "class": "datepicker", + "size": 10, + "id": "entry_date", + }, + ) + entry_time = StringField( + "Heure dépôt", + default="", + validators=[validators.Length(max=5)], + render_kw={ + "class": "timepicker", + "size": 5, + "id": "assi_heure_fin", + }, + ) submit = SubmitField("Enregistrer") cancel = SubmitField("Annuler", render_kw={"formnovalidate": True}) diff --git a/app/models/assiduites.py b/app/models/assiduites.py index b741005e..7c5c1ce2 100644 --- a/app/models/assiduites.py +++ b/app/models/assiduites.py @@ -703,10 +703,14 @@ def is_period_conflicting( date_fin: datetime, collection: Query, collection_cls: Assiduite | Justificatif, + obj_id: int = -1, ) -> bool: """ Vérifie si une date n'entre pas en collision avec les justificatifs ou assiduites déjà présentes + + On peut donner un objet_id pour exclure un objet de la vérification + (utile pour les modifications) """ # On s'assure que les dates soient avec TimeZone @@ -714,7 +718,9 @@ def is_period_conflicting( date_fin = localize_datetime(date_fin) count: int = collection.filter( - collection_cls.date_debut < date_fin, collection_cls.date_fin > date_debut + collection_cls.date_debut < date_fin, + collection_cls.date_fin > date_debut, + collection_cls.id != obj_id, ).count() return count > 0 diff --git a/app/templates/assiduites/pages/edit_assiduite_etud.j2 b/app/templates/assiduites/pages/edit_assiduite_etud.j2 index 8b0930e8..d80d58af 100644 --- a/app/templates/assiduites/pages/edit_assiduite_etud.j2 +++ b/app/templates/assiduites/pages/edit_assiduite_etud.j2 @@ -119,6 +119,21 @@ {{ form.assi_etat.label }} {{ form.assi_etat() }} +
+ {{ form.date_debut.label }} : {{ form.date_debut }} + à {{ form.heure_debut }} + {{ render_field_errors(form, 'date_debut') }} + {{ render_field_errors(form, 'heure_debut') }} +
+ {{ form.date_fin.label }} : {{ form.date_fin }} + à {{ form.heure_fin }} + {{ render_field_errors(form, 'date_fin') }} + {{ render_field_errors(form, 'heure_fin') }} +
+ {{ form.entry_date.label }} : {{ form.entry_date }} à {{ form.entry_time }} + +
+
{# Menu module #}
{{ form.modimpl.label }} : diff --git a/app/views/assiduites.py b/app/views/assiduites.py index b98d61ec..96445b81 100644 --- a/app/views/assiduites.py +++ b/app/views/assiduites.py @@ -66,7 +66,7 @@ from app.models import ( from app.scodoc.codes_cursus import UE_STANDARD from app.auth.models import User -from app.models.assiduites import get_assiduites_justif +from app.models.assiduites import get_assiduites_justif, is_period_conflicting from app.tables.list_etuds import RowEtud, TableEtud import app.tables.liste_assiduites as liste_assi @@ -741,32 +741,6 @@ def ajout_justificatif_etud(): ) -def _verif_date_form_justif( - form: AjoutJustificatifEtudForm, deb: datetime.datetime, fin: datetime.datetime -) -> tuple[datetime.datetime, datetime.datetime]: - """Gère les cas suivants : - - si on indique seulement une date de debut : journée 0h-23h59 - - si on indique date de debut et heures : journée +heure deb/fin - (déjà géré par _get_dates_from_assi_form) - - Si on indique une date de début et de fin sans heures : Journées 0h-23h59 - - Si on indique une date de début et de fin avec heures : On fait un objet avec - datedeb/heuredeb + datefin/heurefin (déjà géré par _get_dates_from_assi_form) - """ - - cas: list[bool] = [ - # cas 1 - not form.date_fin.data and not form.heure_debut.data, - # cas 3 - form.date_fin.data != "" and not form.heure_debut.data, - ] - - if any(cas): - deb = deb.replace(hour=0, minute=0) - fin = fin.replace(hour=23, minute=59) - - return deb, fin - - def _record_justificatif_etud( etud: Identite, form: AjoutJustificatifEtudForm, justif: Justificatif | None = None ) -> bool: @@ -2222,13 +2196,17 @@ def edit_assiduite_etud(assiduite_id: int): 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 + moduleimpl_id = form.modimpl.data if form.modimpl.data is not None else -1 + # Vérifications des dates / horaires + + ok, dt_deb, dt_fin, dt_entry = _get_dates_from_assi_form( + form, etud, from_justif=True, formsemestre=formsemestre + ) + if ok: + if is_period_conflicting( + dt_deb, dt_fin, etud.assiduites, Assiduite, assi.id + ): + form.set_error("La période est en conflit avec une autre assiduité") form.ok = False if form.ok: @@ -2237,6 +2215,10 @@ def edit_assiduite_etud(assiduite_id: int): if moduleimpl_id != -1: assi.set_moduleimpl(moduleimpl_id) + assi.date_debut = dt_deb + assi.date_fin = dt_fin + assi.entry_date = dt_entry + db.session.add(assi) db.session.commit() @@ -2251,12 +2233,19 @@ def edit_assiduite_etud(assiduite_id: int): moduleimpl_id: int | str | None = assi.get_moduleimpl_id() or "" form.modimpl.data = str(moduleimpl_id) + form.date_debut.data = assi.date_debut.strftime(scu.DATE_FMT) + form.heure_debut.data = assi.date_debut.strftime(scu.TIME_FMT) + form.date_fin.data = assi.date_fin.strftime(scu.DATE_FMT) + form.heure_fin.data = assi.date_fin.strftime(scu.TIME_FMT) + form.entry_date.data = assi.entry_date.strftime(scu.DATE_FMT) + form.entry_time.data = assi.entry_date.strftime(scu.TIME_FMT) + return render_template( "assiduites/pages/edit_assiduite_etud.j2", etud=etud, sco=ScoData(etud, formsemestre=formsemestre), form=form, - readonly=readonly, + readonly=True, objet=_preparer_objet("assiduite", assi), title=f"Assiduité {etud.nom_short}", )