Artikelsuche findet die Marke - und Loeschen fragt erst nach dem Bestand
Die Suche verglich bisher einen einzigen Textschnipsel gegen den Namen. Wer
"Vogel Jack and Jones" eintippte, bekam nichts: Dieser Ausdruck steht in
keinem Artikelnamen, und die Marke wurde ueberhaupt nie durchsucht. Jetzt
wird der Suchtext in Woerter zerlegt, jedes muss in Name oder Marke
vorkommen, die Reihenfolge ist egal.
Gefiltert wird in Python und nicht per ILIKE, weil normalisieren() Umlaute
aufloest ("Muehle" findet "Mühle") - auf der Spalte faende ein ILIKE den
gespeicherten Wert nicht wieder. Dieselbe Form nutzt recipes.zuordnung_ziele
schon laenger. Alle Artikellisten haengen an dieser einen Route, die
Verbesserung wirkt also auch bei Gegenstaenden und beim Ein-/Auslagern.
Die Artikelzeile in der App zeigt nun die Marke, sonst waere ein Treffer
darauf nicht zu erklaeren.
Dazu die zweite Haelfte: delete_product hatte keinerlei Schutz und riss
Chargen, Einzelstuecke, Barcodes, Bilder und den ganzen Bewegungsverlauf per
Kaskade mit. Jetzt lehnt der Server mit 409 ab, solange Einzelstuecke oder
Chargen dranhaengen. Bewegungen allein halten bewusst nicht auf - sonst waere
jeder je benutzte Artikel fuer immer unloeschbar. Der Bestaetigungstext im
Web versprach den Verlust des Bestands und stimmte damit nicht mehr.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
94f8ed4db9
commit
264d3886f3
@@ -0,0 +1,95 @@
|
||||
"""Artikel löschen – und wann der Server sich weigert.
|
||||
|
||||
Ohne Sperre reisst ein Klick Chargen, Einzelstücke, Barcodes, Bilder und den
|
||||
gesamten Bewegungsverlauf per Kaskade mit. Geprüft wird deshalb der heutige
|
||||
Bestand. Bewegungen allein halten bewusst NICHT auf, sonst waere jeder je
|
||||
benutzte Artikel fuer immer unloeschbar.
|
||||
|
||||
Geprüft wird nur die Sperre selbst – die Kaskade nicht: Die Tests laufen auf
|
||||
SQLite ohne ``PRAGMA foreign_keys=ON``, eine Kaskaden-Zusicherung waere dort
|
||||
ohne Aussagekraft.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
|
||||
from app.models import BaseUnit, Item, Lot, Product, Role, User
|
||||
from app.routers.products import delete_product
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def admin(db):
|
||||
person = User(username="chef", password_hash="x", role=Role.admin)
|
||||
db.add(person)
|
||||
db.commit()
|
||||
db.refresh(person)
|
||||
return person
|
||||
|
||||
|
||||
def _artikel(db, name="Hammer"):
|
||||
product = Product(name=name, base_unit=BaseUnit.piece, package_size=1,
|
||||
source="manual")
|
||||
db.add(product)
|
||||
db.commit()
|
||||
db.refresh(product)
|
||||
return product
|
||||
|
||||
|
||||
def test_loeschen_ohne_bestand_geht_durch(db, admin):
|
||||
product = _artikel(db)
|
||||
|
||||
delete_product(product_id=product.id, db=db, _=admin)
|
||||
|
||||
assert db.get(Product, product.id) is None
|
||||
|
||||
|
||||
def test_loeschen_mit_einzelstuecken_wird_abgelehnt(db, admin):
|
||||
product = _artikel(db)
|
||||
db.add(Item(uid="ABC12345", product_id=product.id))
|
||||
db.commit()
|
||||
|
||||
with pytest.raises(HTTPException) as fehler:
|
||||
delete_product(product_id=product.id, db=db, _=admin)
|
||||
|
||||
assert fehler.value.status_code == 409
|
||||
assert "Einzelstücke" in fehler.value.detail
|
||||
assert db.get(Product, product.id) is not None
|
||||
|
||||
|
||||
def test_loeschen_mit_chargen_wird_abgelehnt(db, admin):
|
||||
product = _artikel(db)
|
||||
db.add(Lot(product_id=product.id, quantity=5))
|
||||
db.commit()
|
||||
|
||||
with pytest.raises(HTTPException) as fehler:
|
||||
delete_product(product_id=product.id, db=db, _=admin)
|
||||
|
||||
assert fehler.value.status_code == 409
|
||||
assert "Bestand" in fehler.value.detail
|
||||
assert db.get(Product, product.id) is not None
|
||||
|
||||
|
||||
def test_loeschen_nach_leergeraeumter_charge_geht_durch(db, admin):
|
||||
"""Wer alles auslagert, muss den Artikel loswerden können.
|
||||
|
||||
Haelt fest, dass die Sperre am heutigen Bestand haengt und nicht zu einer
|
||||
Verlaufspruefung ausgebaut wird – sonst waere ein einmal benutzter Artikel
|
||||
nie wieder loeschbar.
|
||||
"""
|
||||
product = _artikel(db)
|
||||
lot = Lot(product_id=product.id, quantity=5)
|
||||
db.add(lot)
|
||||
db.commit()
|
||||
db.delete(lot) # wie beim vollstaendigen Auslagern
|
||||
db.commit()
|
||||
|
||||
delete_product(product_id=product.id, db=db, _=admin)
|
||||
|
||||
assert db.get(Product, product.id) is None
|
||||
|
||||
|
||||
def test_unbekannter_artikel_bleibt_ein_404(db, admin):
|
||||
with pytest.raises(HTTPException) as fehler:
|
||||
delete_product(product_id=9999, db=db, _=admin)
|
||||
|
||||
assert fehler.value.status_code == 404
|
||||
Reference in New Issue
Block a user