IT-Stock/app/templates/materiels.html
maxsoch 5088182f20 Création rapide depuis le scan, ajustement de stock flexible, filtres matériels
Un code-barre inconnu scanné propose désormais le même formulaire de
création que /materiels au lieu d'un simple message d'erreur. La
quantité peut être ajustée d'un delta choisi librement (pas figé à ±1)
ou définie directement à une valeur absolue après un inventaire. La
racine "/" sert directement la liste des matériels sans redirection.
La page Matériels gagne un filtre par catégorie, un filtre stock bas,
et un tri incluant un regroupement par catégorie.
2026-07-14 19:17:27 +02:00

132 lines
5.4 KiB
HTML

{% extends "base.html" %}
{% block titre %}Matériels - Gestion de stock IT{% endblock %}
{#
Macro pour une ligne de matériel : utilisée à la fois en affichage plat
et en affichage groupé par catégorie (tri=categorie), pour ne pas
dupliquer le HTML entre les deux.
Chaque ligne est repliée par défaut (juste le résumé, pas les champs
d'édition) : avec beaucoup de matériels, afficher 5 <input> par ligne en
permanence rend la liste illisible et pousse le contenu hors de l'écran.
On ne dépense la largeur d'un vrai formulaire que sur la ligne qu'on
déplie. Voir aussi CLAUDE.md pour le contexte de ce choix.
#}
{% macro ligne_materiel(materiel, categories_aplaties) %}
{% set sous_seuil = materiel.seuil_alerte is not none and materiel.quantite < materiel.seuil_alerte %}
<li>
<details class="ligne-materiel">
<summary>
<span class="noeud-chevron" aria-hidden="true"></span>
<span class="materiel-nom">{{ materiel.nom }}</span>
<span class="materiel-categorie">{{ materiel.categorie.chemin() }}</span>
<span class="materiel-code">{{ materiel.code_barre or "—" }}</span>
<span class="materiel-quantite {{ 'quantite-basse' if sous_seuil else '' }}">{{ materiel.quantite }}</span>
</summary>
<form method="post" action="/materiels/{{ materiel.id }}/modifier" class="formulaire-edition">
<label>Nom
<input type="text" name="nom" value="{{ materiel.nom }}" required>
</label>
<label>Catégorie
<select name="categorie_id" required>
{% for profondeur, categorie in categories_aplaties %}
<option value="{{ categorie.id }}" {{ "selected" if categorie.id == materiel.categorie_id else "" }}>
{{ "— " * profondeur }}{{ categorie.nom }}
</option>
{% endfor %}
</select>
</label>
<label>Code-barre
<input type="text" name="code_barre" value="{{ materiel.code_barre or '' }}">
</label>
<label>Quantité
<input type="number" name="quantite" value="{{ materiel.quantite }}" min="0" required>
</label>
<label>Seuil d'alerte
<input type="number" name="seuil_alerte" value="{{ materiel.seuil_alerte if materiel.seuil_alerte is not none else '' }}" min="0">
</label>
<div class="formulaire-actions">
<button type="submit">Enregistrer</button>
<button type="submit" formaction="/materiels/{{ materiel.id }}/supprimer" class="bouton-danger">Supprimer</button>
</div>
</form>
</details>
</li>
{% endmacro %}
{% block contenu %}
<h1>Matériels</h1>
<form method="get" action="/materiels" class="barre-filtres">
<input type="search" name="q" value="{{ q }}" placeholder="Rechercher par nom ou code-barre…">
<select name="categorie_id">
<option value="">Toutes les catégories</option>
{% for profondeur, categorie in categories_aplaties %}
<option value="{{ categorie.id }}" {{ "selected" if categorie_id == categorie.id|string else "" }}>
{{ "— " * profondeur }}{{ categorie.nom }}
</option>
{% endfor %}
</select>
<select name="tri">
<option value="nom_asc" {{ "selected" if tri == "nom_asc" else "" }}>Nom (A → Z)</option>
<option value="nom_desc" {{ "selected" if tri == "nom_desc" else "" }}>Nom (Z → A)</option>
<option value="quantite_asc" {{ "selected" if tri == "quantite_asc" else "" }}>Quantité (croissant)</option>
<option value="quantite_desc" {{ "selected" if tri == "quantite_desc" else "" }}>Quantité (décroissant)</option>
<option value="categorie" {{ "selected" if tri == "categorie" else "" }}>Regrouper par catégorie</option>
</select>
<label class="case-stock-bas">
<input type="checkbox" name="stock_bas" value="1" {{ "checked" if stock_bas else "" }}>
Stock bas uniquement
</label>
<button type="submit">Filtrer</button>
{% if q or categorie_id or stock_bas or tri != "nom_asc" %}
<a href="/materiels" class="lien-effacer">Réinitialiser</a>
{% endif %}
</form>
<ul class="liste-materiels">
{% if groupes %}
{% for chemin, groupe in groupes %}
<li class="groupe-categorie-entete">{{ chemin }}</li>
{% for materiel in groupe %}
{{ ligne_materiel(materiel, categories_aplaties) }}
{% endfor %}
{% endfor %}
{% else %}
{% for materiel in materiels %}
{{ ligne_materiel(materiel, categories_aplaties) }}
{% endfor %}
{% endif %}
{% if not materiels %}
<li class="liste-vide">
{% if q or categorie_id or stock_bas %}Aucun matériel ne correspond à ces filtres.{% else %}Aucun matériel pour l'instant.{% endif %}
</li>
{% endif %}
</ul>
<h2>Ajouter un matériel</h2>
{% if categories_aplaties %}
<form method="post" action="/materiels" class="formulaire-grille">
<label>Nom <input type="text" name="nom" required></label>
<label>Catégorie
<select name="categorie_id" required>
{% for profondeur, categorie in categories_aplaties %}
<option value="{{ categorie.id }}">{{ "— " * profondeur }}{{ categorie.nom }}</option>
{% endfor %}
</select>
</label>
<label>Code-barre <input type="text" name="code_barre"></label>
<label>Quantité initiale <input type="number" name="quantite" value="0" min="0"></label>
<label>Seuil d'alerte <input type="number" name="seuil_alerte" min="0"></label>
<button type="submit">Créer</button>
</form>
{% else %}
<p>Créez d'abord une <a href="/categories">catégorie</a> avant d'ajouter un matériel.</p>
{% endif %}
{% endblock %}