2026-07-14 16:38:59 +00:00
|
|
|
"""
|
2026-07-14 17:06:37 +00:00
|
|
|
Tests du flux principal : créer une arborescence de catégories, créer un
|
2026-07-14 17:17:27 +00:00
|
|
|
matériel, le retrouver (ou le créer) par scan, ajuster son stock de deux
|
|
|
|
|
façons différentes, et vérifier que l'alerte de stock bas se déclenche
|
|
|
|
|
(elle est simplement affichée dans la console tant qu'aucun SMTP n'est
|
|
|
|
|
configuré, voir app/email_alerts.py).
|
2026-07-14 16:38:59 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from sqlmodel import Session, select
|
|
|
|
|
|
2026-07-14 17:06:37 +00:00
|
|
|
from app.models import Categorie, DestinataireAlerte, Materiel
|
2026-07-14 16:38:59 +00:00
|
|
|
|
|
|
|
|
|
2026-07-14 17:06:37 +00:00
|
|
|
def _creer_sous_categorie(session: Session) -> Categorie:
|
|
|
|
|
"""Crée une petite arborescence à 2 niveaux (Ordinateurs > Portables)
|
|
|
|
|
pour les tests qui n'ont pas besoin de tester la profondeur illimitée
|
|
|
|
|
elle-même — voir test_categories.py pour ça."""
|
|
|
|
|
racine = Categorie(nom="Ordinateurs")
|
|
|
|
|
session.add(racine)
|
2026-07-14 16:38:59 +00:00
|
|
|
session.commit()
|
2026-07-14 17:06:37 +00:00
|
|
|
session.refresh(racine)
|
2026-07-14 16:38:59 +00:00
|
|
|
|
2026-07-14 17:06:37 +00:00
|
|
|
enfant = Categorie(nom="Portables", parent_id=racine.id)
|
|
|
|
|
session.add(enfant)
|
2026-07-14 16:38:59 +00:00
|
|
|
session.commit()
|
2026-07-14 17:06:37 +00:00
|
|
|
session.refresh(enfant)
|
|
|
|
|
return enfant
|
2026-07-14 16:38:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_creation_materiel(client, session):
|
|
|
|
|
sous_categorie = _creer_sous_categorie(session)
|
|
|
|
|
|
|
|
|
|
reponse = client.post(
|
|
|
|
|
"/materiels",
|
|
|
|
|
data={
|
|
|
|
|
"nom": "PC Dell XPS 13",
|
2026-07-14 17:06:37 +00:00
|
|
|
"categorie_id": sous_categorie.id,
|
2026-07-14 16:38:59 +00:00
|
|
|
"code_barre": "1234567890123",
|
|
|
|
|
"quantite": "5",
|
|
|
|
|
"seuil_alerte": "2",
|
|
|
|
|
},
|
|
|
|
|
follow_redirects=False,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert reponse.status_code == 303
|
|
|
|
|
materiel = session.exec(select(Materiel)).first()
|
|
|
|
|
assert materiel is not None
|
|
|
|
|
assert materiel.quantite == 5
|
|
|
|
|
|
|
|
|
|
|
2026-07-14 17:17:27 +00:00
|
|
|
def test_racine_affiche_la_liste_des_materiels(client, session):
|
|
|
|
|
""" "/" doit afficher directement les matériels, pas rediriger."""
|
|
|
|
|
reponse = client.get("/", follow_redirects=False)
|
|
|
|
|
|
|
|
|
|
assert reponse.status_code == 200
|
|
|
|
|
assert "Matériels" in reponse.text
|
|
|
|
|
|
|
|
|
|
|
2026-07-14 16:38:59 +00:00
|
|
|
def test_scan_trouve_le_materiel_par_code_barre(client, session):
|
|
|
|
|
sous_categorie = _creer_sous_categorie(session)
|
|
|
|
|
session.add(
|
|
|
|
|
Materiel(
|
|
|
|
|
nom="Câble RJ45 2m",
|
2026-07-14 17:06:37 +00:00
|
|
|
categorie_id=sous_categorie.id,
|
2026-07-14 16:38:59 +00:00
|
|
|
code_barre="9998887776665",
|
|
|
|
|
quantite=10,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
session.commit()
|
|
|
|
|
|
|
|
|
|
reponse = client.post("/scan", data={"code_barre": "9998887776665"})
|
|
|
|
|
|
|
|
|
|
assert reponse.status_code == 200
|
|
|
|
|
assert "Câble RJ45 2m" in reponse.text
|
|
|
|
|
|
|
|
|
|
|
2026-07-14 17:17:27 +00:00
|
|
|
def test_scan_code_inconnu_propose_la_creation(client, session):
|
|
|
|
|
"""Un code-barre sans matériel correspondant doit proposer le
|
|
|
|
|
formulaire de création rapide, pas juste un message d'erreur."""
|
2026-07-14 16:38:59 +00:00
|
|
|
_creer_sous_categorie(session)
|
|
|
|
|
|
|
|
|
|
reponse = client.post("/scan", data={"code_barre": "0000000000000"})
|
|
|
|
|
|
|
|
|
|
assert reponse.status_code == 200
|
2026-07-14 17:17:27 +00:00
|
|
|
assert "0000000000000" in reponse.text
|
|
|
|
|
assert 'name="categorie_id"' in reponse.text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_creation_depuis_le_scan(client, session):
|
|
|
|
|
sous_categorie = _creer_sous_categorie(session)
|
|
|
|
|
|
|
|
|
|
reponse = client.post(
|
|
|
|
|
"/scan/creer",
|
|
|
|
|
data={
|
|
|
|
|
"nom": "Clavier sans fil",
|
|
|
|
|
"code_barre": "5551112223334",
|
|
|
|
|
"categorie_id": sous_categorie.id,
|
|
|
|
|
"quantite": "4",
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert reponse.status_code == 200
|
|
|
|
|
assert "Clavier sans fil" in reponse.text
|
|
|
|
|
materiel = session.exec(select(Materiel).where(Materiel.code_barre == "5551112223334")).first()
|
|
|
|
|
assert materiel is not None
|
|
|
|
|
assert materiel.quantite == 4
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_ajuster_quantite_avec_un_delta_choisi(client, session):
|
|
|
|
|
sous_categorie = _creer_sous_categorie(session)
|
|
|
|
|
materiel = Materiel(nom="Écran 24 pouces", categorie_id=sous_categorie.id, quantite=10)
|
|
|
|
|
session.add(materiel)
|
|
|
|
|
session.commit()
|
|
|
|
|
session.refresh(materiel)
|
|
|
|
|
|
|
|
|
|
reponse = client.post(f"/scan/{materiel.id}/ajuster", data={"quantite": "4", "sens": "retirer"})
|
|
|
|
|
|
|
|
|
|
assert reponse.status_code == 200
|
|
|
|
|
session.refresh(materiel)
|
|
|
|
|
assert materiel.quantite == 6
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_definir_quantite_directement(client, session):
|
|
|
|
|
sous_categorie = _creer_sous_categorie(session)
|
|
|
|
|
materiel = Materiel(nom="Écran 24 pouces", categorie_id=sous_categorie.id, quantite=10)
|
|
|
|
|
session.add(materiel)
|
|
|
|
|
session.commit()
|
|
|
|
|
session.refresh(materiel)
|
|
|
|
|
|
|
|
|
|
reponse = client.post(f"/scan/{materiel.id}/definir", data={"quantite": "17"})
|
|
|
|
|
|
|
|
|
|
assert reponse.status_code == 200
|
|
|
|
|
session.refresh(materiel)
|
|
|
|
|
assert materiel.quantite == 17
|
2026-07-14 16:38:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_alerte_declenchee_sous_le_seuil(client, session, capsys):
|
|
|
|
|
sous_categorie = _creer_sous_categorie(session)
|
|
|
|
|
materiel = Materiel(
|
|
|
|
|
nom="Souris USB",
|
2026-07-14 17:06:37 +00:00
|
|
|
categorie_id=sous_categorie.id,
|
2026-07-14 16:38:59 +00:00
|
|
|
quantite=3,
|
|
|
|
|
seuil_alerte=5,
|
|
|
|
|
)
|
|
|
|
|
session.add(materiel)
|
|
|
|
|
session.commit()
|
|
|
|
|
session.refresh(materiel)
|
|
|
|
|
session.add(DestinataireAlerte(email="it-dept@clinique.local"))
|
|
|
|
|
session.commit()
|
|
|
|
|
|
2026-07-14 17:17:27 +00:00
|
|
|
reponse = client.post(f"/scan/{materiel.id}/ajuster", data={"quantite": "1", "sens": "retirer"})
|
2026-07-14 16:38:59 +00:00
|
|
|
|
|
|
|
|
assert reponse.status_code == 200
|
|
|
|
|
sortie = capsys.readouterr().out
|
|
|
|
|
assert "EMAIL SIMULÉ" in sortie
|
|
|
|
|
assert "Souris USB" in sortie
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_pas_alerte_si_stock_suffisant(client, session, capsys):
|
|
|
|
|
sous_categorie = _creer_sous_categorie(session)
|
|
|
|
|
materiel = Materiel(
|
|
|
|
|
nom="Clavier USB",
|
2026-07-14 17:06:37 +00:00
|
|
|
categorie_id=sous_categorie.id,
|
2026-07-14 16:38:59 +00:00
|
|
|
quantite=10,
|
|
|
|
|
seuil_alerte=5,
|
|
|
|
|
)
|
|
|
|
|
session.add(materiel)
|
|
|
|
|
session.commit()
|
|
|
|
|
session.refresh(materiel)
|
|
|
|
|
session.add(DestinataireAlerte(email="it-dept@clinique.local"))
|
|
|
|
|
session.commit()
|
|
|
|
|
|
2026-07-14 17:17:27 +00:00
|
|
|
reponse = client.post(f"/scan/{materiel.id}/ajuster", data={"quantite": "1", "sens": "retirer"})
|
2026-07-14 16:38:59 +00:00
|
|
|
|
2026-07-14 17:17:27 +00:00
|
|
|
assert reponse.status_code == 200
|
2026-07-14 16:38:59 +00:00
|
|
|
sortie = capsys.readouterr().out
|
|
|
|
|
assert "EMAIL SIMULÉ" not in sortie
|