forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -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,
|
||||
|
@ -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,6 +389,13 @@ class RowAssiJusti(tb.Row):
|
||||
html.append(f'<a title="Détails" href="{url}">ℹ️</a>')
|
||||
|
||||
# Modifier
|
||||
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"],
|
||||
|
@ -90,9 +90,9 @@ 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>
|
||||
{# 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 %}
|
||||
|
||||
@ -61,11 +63,27 @@ 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) #}
|
||||
{# Liste des fichiers existants #}
|
||||
{% if justif and nb_files > 0 %}
|
||||
<div>
|
||||
<div>{{nb_files}} fichiers justificatifs déposés
|
||||
{% if filenames|length < nb_files %}
|
||||
, dont {{filenames|length}} vous sont accessibles
|
||||
{% endif %}
|
||||
<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>
|
||||
</div>
|
||||
{% endif %}
|
||||
{# Ajout fichier(s) justificatif(s) #}
|
||||
<div>
|
||||
<div>{{ form.fichiers.label }}</div>
|
||||
{{ form.fichiers() }}
|
||||
@ -83,10 +101,11 @@ div.submit > input {
|
||||
</fieldset>
|
||||
</form>
|
||||
</section>
|
||||
{% if tableau %}
|
||||
<section class="assi-liste">
|
||||
{{tableau | safe }}
|
||||
</section>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock app_content %}
|
||||
@ -108,4 +127,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 %}
|
||||
|
@ -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/<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(
|
||||
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.assi_raison.data,
|
||||
raison=form.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 = "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:
|
||||
|
Loading…
Reference in New Issue
Block a user