Răsfoiți Sursa

Default fetch-prices to booked_only=True; drop discount reversal logic

fetch-prices is only safe for booked days where the platform price is the
locked-in booking rate. Making booked_only=True the default prevents
accidentally importing dirty open-day prices. The discount reversal on open
days was never exercised in production and was conceptually wrong — removed
entirely so prices are always written as-is (net = base, no discount).
ZiB 4 luni în urmă
părinte
comite
cc34b0f041

+ 7 - 19
room_cal/actions/fetch_prices.py

@@ -2,7 +2,6 @@ import asyncio
 from datetime import date, timedelta
 from typing import TYPE_CHECKING
 
-from room_cal.discount import Discount, DiscountType
 from room_cal.pricing import CalPrice
 from room_cal.pricing.calc import list_to_net
 from room_cal.reservations import Reservation
@@ -20,7 +19,7 @@ async def fetch_prices(
   *,
   api: 'ServiceAPI | None' = None,
   service: str | None = None,
-  booked_only: bool = False,
+  booked_only: bool = True,
 ) -> FetchResult[list[dict]]:
   """Fetch per-service list prices from the API and write net prices to the calendar.
 
@@ -31,8 +30,10 @@ async def fetch_prices(
 
   If `service` is given, only that service's prices are used; otherwise the
   first service with a non-None price wins.
-  If `booked_only` is True, only dates that have an active reservation are updated;
-  open days are skipped regardless of what the platform reports.
+  If `booked_only` is True (the default), only dates with an active reservation are
+  updated; open days are skipped. Pass booked_only=False for initial data imports,
+  but note that prices are written as-is with no discount applied — callers are
+  responsible for following up with local_sync or apply_discounts if needed.
   """
   from room_cal.service_api import ServiceAPI as _ServiceAPI
   if api is None:
@@ -44,10 +45,9 @@ async def fetch_prices(
 
   service_keys = [service] if service else _services()
   cal = CalPrice()
-  existing_events, res_events, discount_by_date = await asyncio.gather(
+  existing_events, res_events = await asyncio.gather(
     cal.list(start_date, end_date),
     Reservation().list(start_date, end_date),
-    Discount().get_range(start_date, end_date),
   )
   existing_by_date = {e.start.date(): e for e in existing_events}
 
@@ -78,18 +78,6 @@ async def fetch_prices(
     if net is None:
       continue
     d = date.fromisoformat(ds)
-    discount_rec = discount_by_date.get(d)
-    # On booked days the platform price is the locked-in booking rate; the current
-    # discount is irrelevant, so store net as-is with no discount attached.
-    # On open days, reverse the local discount so CalPrice.set can re-apply it
-    # consistently without drifting the base on each fetch→push cycle.
-    base = net
-    if discount_rec and not booked_svc:
-      if discount_rec.type == DiscountType.FLAT:
-        base = net + int(discount_rec.value)
-      else:
-        base = round(net / (1 - discount_rec.value / 100))
-    effective_discount = None if booked_svc else discount_rec
     existing = existing_by_date.get(d)
     if existing is None:
       changed = True
@@ -97,7 +85,7 @@ async def fetch_prices(
       xd = safe_json_loads(existing.x_data)
       if (xd or {}).get('net') != net:
         changed = True
-    await cal.set(d, base, existing=existing, discount_rec=effective_discount)
+    await cal.set(d, net, existing=existing, discount_rec=None)
     results.append({'date': d, 'net': net})
 
   return FetchResult(data=results, changed=changed)

+ 2 - 2
room_cal/workflows/prices.py

@@ -84,13 +84,13 @@ async def workflow_delete_discount(target_date: date, bg: BackgroundTasks):
 async def _periodic_fetch_short(api: 'ServiceAPI') -> None:
   start = local_today()
   window = get_config().global_.reservation_window_days
-  await fetch_prices(start, start + timedelta(days=window), api=api, booked_only=True)
+  await fetch_prices(start, start + timedelta(days=window), api=api)
 
 
 async def _periodic_fetch_long(api: 'ServiceAPI') -> None:
   start = local_today()
   window = get_config().global_.long_window_days
-  await fetch_prices(start, start + timedelta(days=window), api=api, booked_only=True)
+  await fetch_prices(start, start + timedelta(days=window), api=api)
 
 
 register_periodic(_periodic_fetch_short, timedelta(hours=6))

+ 1 - 1
room_cal/workflows/reservations.py

@@ -33,7 +33,7 @@ async def sync_reservations(
   else:
     eff_start, eff_end = start_date, end_date
   await _push(push_closed(eff_start, eff_end, api=api), schedule)
-  await _push(fetch_prices(eff_start, eff_end, api=api, booked_only=True), schedule)
+  await _push(fetch_prices(eff_start, eff_end, api=api), schedule)
   await _push(local_sync(eff_start, eff_end), schedule)
 
 

+ 1 - 1
tests/test_action_chains.py

@@ -174,7 +174,7 @@ async def test_fetch_prices_syncs_api_prices_to_caldav():
   before = {d for d in iter_dates(scan_start, scan_end) if await cal._get_prices(d) is not None}
 
   try:
-    result = await fetch_prices(scan_start, scan_end, api=api)
+    result = await fetch_prices(scan_start, scan_end, api=api, booked_only=False)
     assert result.data, "fetch_prices returned nothing despite API reporting prices"
 
     for r in result.data: