|
|
@@ -0,0 +1,69 @@
|
|
|
+import pytest
|
|
|
+from datetime import date
|
|
|
+from types import SimpleNamespace
|
|
|
+
|
|
|
+from room_cal.discount import DiscountData, DiscountType
|
|
|
+from room_cal.pricing import CalPrice
|
|
|
+from room_cal.pricing.price_calendar import PriceData
|
|
|
+from room_cal.rules.discount.min_price import RULE_NAME, run
|
|
|
+
|
|
|
+
|
|
|
+def _stub_prices(monkeypatch, bases: dict[date, int]):
|
|
|
+ async def _get(self, start_date, end_date):
|
|
|
+ return {str(d): PriceData(base=base, net=base) for d, base in bases.items()}
|
|
|
+ monkeypatch.setattr(CalPrice, 'get', _get)
|
|
|
+
|
|
|
+
|
|
|
+def _stub_config(monkeypatch, min_net: int):
|
|
|
+ cfg = SimpleNamespace(rules=SimpleNamespace(min_price=SimpleNamespace(min_net=min_net)))
|
|
|
+ monkeypatch.setattr('room_cal.rules.discount.min_price.get_config', lambda: cfg)
|
|
|
+
|
|
|
+
|
|
|
+def test_rule_registered():
|
|
|
+ assert RULE_NAME == 'min_price'
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+async def test_empty_input_returns_empty():
|
|
|
+ assert await run(date(2026, 1, 1), date(2026, 1, 1), {}) == {}
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+async def test_percent_discount_clamped_to_floor(monkeypatch):
|
|
|
+ d = date(2026, 1, 10)
|
|
|
+ _stub_prices(monkeypatch, {d: 100})
|
|
|
+ _stub_config(monkeypatch, 52)
|
|
|
+ data = {d: DiscountData(type=DiscountType.PERCENT, value=60)}
|
|
|
+ result = await run(d, d, data)
|
|
|
+ # headroom = 100 - 52 = 48 -> max_pct = 48%
|
|
|
+ assert result[d].value == 48
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+async def test_flat_discount_clamped_to_floor(monkeypatch):
|
|
|
+ d = date(2026, 1, 10)
|
|
|
+ _stub_prices(monkeypatch, {d: 100})
|
|
|
+ _stub_config(monkeypatch, 52)
|
|
|
+ data = {d: DiscountData(type=DiscountType.FLAT, value=60)}
|
|
|
+ result = await run(d, d, data)
|
|
|
+ assert result[d].value == 48
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+async def test_discount_under_floor_passes_through(monkeypatch):
|
|
|
+ d = date(2026, 1, 10)
|
|
|
+ _stub_prices(monkeypatch, {d: 100})
|
|
|
+ _stub_config(monkeypatch, 52)
|
|
|
+ data = {d: DiscountData(type=DiscountType.PERCENT, value=30)}
|
|
|
+ result = await run(d, d, data)
|
|
|
+ assert result[d].value == 30
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+async def test_base_at_or_below_floor_drops_discount(monkeypatch):
|
|
|
+ d = date(2026, 1, 10)
|
|
|
+ _stub_prices(monkeypatch, {d: 50})
|
|
|
+ _stub_config(monkeypatch, 52)
|
|
|
+ data = {d: DiscountData(type=DiscountType.PERCENT, value=10)}
|
|
|
+ result = await run(d, d, data)
|
|
|
+ assert d not in result
|