Gérer manuellement les périodes de vacances
Some checks are pending
CI - Tests et Syntax / lint-and-test (push) Waiting to run

This commit is contained in:
root 2026-08-20 21:24:37 +00:00
parent 82cd35d4ae
commit a086103343
2 changed files with 39 additions and 0 deletions

View file

@ -38,6 +38,8 @@
<div class="card mb-3"><div class="card-header"><strong>Importer les calendriers</strong></div><div class="card-body"><div class="row g-2"><div class="col-md-6"><form method="post" action="{{ url_for('planning.import_school_vacations') }}"><input type="hidden" name="csrf_token" value="{{ csrf_token() }}"><input type="hidden" name="year" value="{{ year }}"><div class="input-group"><select class="form-select" name="zone"><option value="C" selected>Zone C</option><option value="B">Zone B</option><option value="A">Zone A</option></select><button class="btn btn-outline-primary">Importer vacances</button></div><small class="text-muted">Changer de zone remplace les périodes scolaires importées pour lautre zone.</small></form></div><div class="col-md-6"><form method="post" action="{{ url_for('planning.import_public_holidays') }}"><input type="hidden" name="csrf_token" value="{{ csrf_token() }}"><input type="hidden" name="year" value="{{ year }}"><button class="btn btn-outline-primary">Importer jours fériés {{ year }}</button></form></div></div></div></div> <div class="card mb-3"><div class="card-header"><strong>Importer les calendriers</strong></div><div class="card-body"><div class="row g-2"><div class="col-md-6"><form method="post" action="{{ url_for('planning.import_school_vacations') }}"><input type="hidden" name="csrf_token" value="{{ csrf_token() }}"><input type="hidden" name="year" value="{{ year }}"><div class="input-group"><select class="form-select" name="zone"><option value="C" selected>Zone C</option><option value="B">Zone B</option><option value="A">Zone A</option></select><button class="btn btn-outline-primary">Importer vacances</button></div><small class="text-muted">Changer de zone remplace les périodes scolaires importées pour lautre zone.</small></form></div><div class="col-md-6"><form method="post" action="{{ url_for('planning.import_public_holidays') }}"><input type="hidden" name="csrf_token" value="{{ csrf_token() }}"><input type="hidden" name="year" value="{{ year }}"><button class="btn btn-outline-primary">Importer jours fériés {{ year }}</button></form></div></div></div></div>
<div class="card mb-3"><div class="card-header"><strong>Vacances personnalisées</strong><small class="d-block text-muted">Ajoutez une période manuelle ou supprimez une période existante. Les jours fériés sont gérés séparément.</small></div><div class="card-body"><form method="post" action="{{ url_for('planning.add_manual_vacation') }}" class="row g-2 align-items-end"><input type="hidden" name="csrf_token" value="{{ csrf_token() }}"><input type="hidden" name="year" value="{{ year }}"><div class="col-md-4"><label class="form-label">Intitulé</label><input class="form-control" name="name" placeholder="Ex. fermeture exceptionnelle" required></div><div class="col-md-3"><label class="form-label">Début</label><input class="form-control" type="date" name="start_date" required></div><div class="col-md-3"><label class="form-label">Fin</label><input class="form-control" type="date" name="end_date" required></div><div class="col-md-2"><button class="btn btn-outline-success w-100">Ajouter</button></div></form><div class="table-responsive mt-3"><table class="table table-sm align-middle mb-0"><thead><tr><th>Période</th><th>Dates</th><th>Origine</th><th></th></tr></thead><tbody>{% for closure in closures if closure.closure_type in ('vacances', 'vacances_scolaires') %}<tr><td>{{ closure.name }}</td><td>{{ closure.start_date.strftime('%d/%m/%Y') }} → {{ closure.end_date.strftime('%d/%m/%Y') }}</td><td>{% if closure.closure_type == 'vacances_scolaires' %}<span class="badge bg-info text-dark">Importée</span>{% else %}<span class="badge bg-secondary">Manuelle</span>{% endif %}</td><td><form method="post" action="{{ url_for('planning.delete_vacation', id=closure.id) }}"><input type="hidden" name="csrf_token" value="{{ csrf_token() }}"><button class="btn btn-sm btn-outline-danger" title="Supprimer"><i class="bi bi-trash"></i></button></form></td></tr>{% else %}<tr><td colspan="4" class="text-muted">Aucune période de vacances enregistrée.</td></tr>{% endfor %}</tbody></table></div></div></div>
<div class="card mb-3"><div class="card-header"><strong>Permanences dans les vacances</strong><small class="d-block text-muted">Sélectionnez plusieurs dates puis lhoraire type à appliquer.</small></div><div class="card-body"><form method="post" action="{{ url_for('planning.save_permanences') }}"><input type="hidden" name="csrf_token" value="{{ csrf_token() }}"><input type="hidden" name="year" value="{{ year }}"><div class="row g-2 align-items-end"><div class="col-md-8"><label class="form-label">Horaire type</label><select class="form-select" name="template_id" required><option value="">Choisir…</option>{% for template in templates %}<option value="{{ template.id }}">{{ template.name }} ({{ template.start_time.strftime('%H:%M') }}{{ template.end_time.strftime('%H:%M') }})</option>{% endfor %}</select></div><div class="col-md-4"><button class="btn btn-success w-100" {% if not templates %}disabled{% endif %}>Affecter les dates sélectionnées</button></div></div>{% for group in permanence_groups %}<div class="border-top mt-3 pt-2"><h6 class="mb-2"><i class="bi bi-calendar2-week me-1"></i>{{ group.closure.name }} <small class="text-muted">({{ group.closure.start_date.strftime('%d/%m/%Y') }} au {{ group.closure.end_date.strftime('%d/%m/%Y') }})</small></h6><div class="row g-2">{% for option in group.options %}<div class="col-xl-3 col-lg-4 col-md-6"><label class="border rounded p-2 d-block"><input type="checkbox" name="work_dates" value="{{ option.date.isoformat() }}" {% if option.entry %}checked{% endif %}> <strong>{{ days.get(option.date.weekday()) }} {{ option.date.strftime('%d/%m/%Y') }}</strong><br><small>{% if option.entry and option.entry.template %}{{ option.entry.template.name }} · {{ option.entry.start_time.strftime('%H:%M') }}{{ option.entry.end_time.strftime('%H:%M') }}{% else %}Pas de permanence{% endif %}</small></label></div>{% endfor %}</div></div>{% else %}<div class="text-muted mt-3">Aucune période de vacances importée pour cette période. Importez dabord le calendrier scolaire.</div>{% endfor %}</form> <div class="card mb-3"><div class="card-header"><strong>Permanences dans les vacances</strong><small class="d-block text-muted">Sélectionnez plusieurs dates puis lhoraire type à appliquer.</small></div><div class="card-body"><form method="post" action="{{ url_for('planning.save_permanences') }}"><input type="hidden" name="csrf_token" value="{{ csrf_token() }}"><input type="hidden" name="year" value="{{ year }}"><div class="row g-2 align-items-end"><div class="col-md-8"><label class="form-label">Horaire type</label><select class="form-select" name="template_id" required><option value="">Choisir…</option>{% for template in templates %}<option value="{{ template.id }}">{{ template.name }} ({{ template.start_time.strftime('%H:%M') }}{{ template.end_time.strftime('%H:%M') }})</option>{% endfor %}</select></div><div class="col-md-4"><button class="btn btn-success w-100" {% if not templates %}disabled{% endif %}>Affecter les dates sélectionnées</button></div></div>{% for group in permanence_groups %}<div class="border-top mt-3 pt-2"><h6 class="mb-2"><i class="bi bi-calendar2-week me-1"></i>{{ group.closure.name }} <small class="text-muted">({{ group.closure.start_date.strftime('%d/%m/%Y') }} au {{ group.closure.end_date.strftime('%d/%m/%Y') }})</small></h6><div class="row g-2">{% for option in group.options %}<div class="col-xl-3 col-lg-4 col-md-6"><label class="border rounded p-2 d-block"><input type="checkbox" name="work_dates" value="{{ option.date.isoformat() }}" {% if option.entry %}checked{% endif %}> <strong>{{ days.get(option.date.weekday()) }} {{ option.date.strftime('%d/%m/%Y') }}</strong><br><small>{% if option.entry and option.entry.template %}{{ option.entry.template.name }} · {{ option.entry.start_time.strftime('%H:%M') }}{{ option.entry.end_time.strftime('%H:%M') }}{% else %}Pas de permanence{% endif %}</small></label></div>{% endfor %}</div></div>{% else %}<div class="text-muted mt-3">Aucune période de vacances importée pour cette période. Importez dabord le calendrier scolaire.</div>{% endfor %}</form>
{% set selected_permanences = permanence_options|selectattr('entry')|list %} {% set selected_permanences = permanence_options|selectattr('entry')|list %}
<hr><h6><i class="bi bi-list-check me-1"></i>Récapitulatif des permanences</h6> <hr><h6><i class="bi bi-list-check me-1"></i>Récapitulatif des permanences</h6>

View file

@ -320,6 +320,43 @@ def import_public_holidays():
return _redirect(year) return _redirect(year)
@planning_bp.route("/time/vacation", methods=["POST"])
@login_required
def add_manual_vacation():
"""Ajoute une période de vacances personnalisée."""
try:
start_date = datetime.strptime(request.form["start_date"], "%Y-%m-%d").date()
end_date = datetime.strptime(request.form["end_date"], "%Y-%m-%d").date()
except (KeyError, ValueError):
flash("Dates de vacances invalides.", "danger")
return _redirect(request.form.get("year", type=int))
if end_date < start_date:
flash("La date de fin doit être postérieure ou égale à la date de début.", "danger")
return _redirect(start_date.year)
db.session.add(CollegeClosure(
name=(request.form.get("name") or "Vacances personnalisées").strip(),
start_date=start_date, end_date=end_date,
closure_type="vacances", work_hours_type="none",
notes="Période ajoutée manuellement",
))
db.session.commit()
flash("Période de vacances ajoutée.", "success")
return _redirect(start_date.year)
@planning_bp.route("/time/vacation/<int:id>/delete", methods=["POST"])
@login_required
def delete_vacation(id):
vacation = CollegeClosure.query.filter(
CollegeClosure.id == id,
CollegeClosure.closure_type.in_(["vacances", "vacances_scolaires"]),
).first_or_404()
db.session.delete(vacation)
db.session.commit()
flash("Période de vacances supprimée.", "success")
return _redirect()
@planning_bp.route("/time/permanences", methods=["POST"]) @planning_bp.route("/time/permanences", methods=["POST"])
@login_required @login_required
def save_permanences(): def save_permanences():