from datetime import date, timedelta import pytest from app.services.stock import StockError, check_in, check_out, current_stock def _checkin(db, product, qty, unit, best_before=None): lot = check_in(db, product, qty, unit, best_before, None, None) db.commit() return lot def test_checkin_creates_lot_in_base_units(db, rice): _checkin(db, rice, 3, "package") # 1500 g assert current_stock(db, rice.id) == 1500 def test_checkout_partial_amount(db, rice): _checkin(db, rice, 3, "package") # 1500 g check_out(db, rice, 200, "g", None) db.commit() assert current_stock(db, rice.id) == 1300 def test_fefo_takes_earliest_expiry_first(db, rice): soon = date.today() + timedelta(days=5) later = date.today() + timedelta(days=60) # Zuerst die später ablaufende Charge einlagern ... _checkin(db, rice, 500, "g", best_before=later) # ... dann die früher ablaufende. _checkin(db, rice, 500, "g", best_before=soon) check_out(db, rice, 400, "g", None) db.commit() # Die früh ablaufende Charge (soon) muss zuerst reduziert worden sein. from app.models import Lot lots = {l.best_before: l.quantity for l in db.query(Lot).all()} assert lots[soon] == 100 assert lots[later] == 500 def test_fefo_spans_multiple_lots_and_removes_empty(db, rice): soon = date.today() + timedelta(days=5) later = date.today() + timedelta(days=60) _checkin(db, rice, 500, "g", best_before=soon) _checkin(db, rice, 500, "g", best_before=later) check_out(db, rice, 700, "g", None) # 500 (soon) + 200 (later) db.commit() from app.models import Lot lots = db.query(Lot).all() assert len(lots) == 1 # leere soon-Charge entfernt assert lots[0].best_before == later assert lots[0].quantity == 300 def test_null_best_before_is_last(db, rice): dated = date.today() + timedelta(days=30) _checkin(db, rice, 300, "g", best_before=None) _checkin(db, rice, 300, "g", best_before=dated) check_out(db, rice, 300, "g", None) db.commit() from app.models import Lot remaining = db.query(Lot).all() # Die datierte Charge wird zuerst genommen, die NULL-Charge bleibt. assert len(remaining) == 1 assert remaining[0].best_before is None def test_checkout_more_than_available_raises(db, rice): _checkin(db, rice, 100, "g") with pytest.raises(StockError): check_out(db, rice, 200, "g", None)