|
|
@@ -23,6 +23,11 @@ ACTION_SPEC = ('diff', [])
|
|
|
_PRICE_PREFIX = 'Price: $'
|
|
|
|
|
|
|
|
|
+def _clamp_future(start_date: date) -> date:
|
|
|
+ """Past dates are not compared — only reservation data has historical value."""
|
|
|
+ return max(start_date, local_today())
|
|
|
+
|
|
|
+
|
|
|
async def _timed(key: str, coro, timings: dict):
|
|
|
t0 = time.perf_counter()
|
|
|
result = await coro
|
|
|
@@ -48,7 +53,9 @@ async def diff(
|
|
|
rule_closed — {pipeline_name: [...]} Room Closed (rule-sourced) vs rule output
|
|
|
orphans — Room Closed/Discount events with missing or unrecognized source
|
|
|
|
|
|
- No writes are performed.
|
|
|
+ No writes are performed. Past dates are compared only for reservation data
|
|
|
+ (reservations, double_bookings); prices, closed, and rule categories clamp
|
|
|
+ to today-forward — historical values there are meaningless to users.
|
|
|
"""
|
|
|
from room_cal.service_api import ServiceAPI as _ServiceAPI
|
|
|
if api is None:
|
|
|
@@ -86,6 +93,10 @@ async def _diff_prices(
|
|
|
"""
|
|
|
from room_cal.reservations import Reservation
|
|
|
|
|
|
+ start_date = _clamp_future(start_date)
|
|
|
+ if start_date > end_date:
|
|
|
+ return []
|
|
|
+
|
|
|
from datetime import datetime
|
|
|
backend = get_backend()
|
|
|
start_dt = datetime(start_date.year, start_date.month, start_date.day)
|
|
|
@@ -115,11 +126,9 @@ async def _diff_prices(
|
|
|
for d in iter_dates(e.start.date(), last_night):
|
|
|
booked_svc_by_date[d] = svc
|
|
|
|
|
|
- today = local_today()
|
|
|
results: list[dict] = []
|
|
|
- for ds in (d.isoformat() for d in iter_dates(start_date, end_date)):
|
|
|
- d = date.fromisoformat(ds)
|
|
|
- is_past = d < today
|
|
|
+ for d in iter_dates(start_date, end_date):
|
|
|
+ ds = d.isoformat()
|
|
|
local = cal_prices.get(ds)
|
|
|
remote = api_prices.get(ds, {})
|
|
|
has_diff = False
|
|
|
@@ -129,8 +138,6 @@ async def _diff_prices(
|
|
|
rp = remote.get(svc)
|
|
|
if lp is None and rp is None:
|
|
|
continue
|
|
|
- if svc == 'booking' and is_past and rp is None:
|
|
|
- continue
|
|
|
booked_svc = booked_svc_by_date.get(d)
|
|
|
if booked_svc is not None and svc != booked_svc:
|
|
|
continue
|
|
|
@@ -157,6 +164,10 @@ async def _diff_closed(
|
|
|
|
|
|
Each row: {'date', 'local': list[str]|None, 'remote': list[str]|None}
|
|
|
"""
|
|
|
+ start_date = _clamp_future(start_date)
|
|
|
+ if start_date > end_date:
|
|
|
+ return []
|
|
|
+
|
|
|
closed_cal = Closed()
|
|
|
cal_events = await closed_cal.list(start_date, end_date)
|
|
|
cal_by_date: dict[str, list[str]] = {}
|
|
|
@@ -168,18 +179,12 @@ async def _diff_closed(
|
|
|
api_by_date = await api.get_closed_by_date(start_date, end_date)
|
|
|
api_by_date = {ds: sorted(svcs) for ds, svcs in api_by_date.items()}
|
|
|
|
|
|
- today = local_today()
|
|
|
all_dates = sorted(set(cal_by_date) | set(api_by_date))
|
|
|
results: list[dict] = []
|
|
|
for ds in all_dates:
|
|
|
local = cal_by_date.get(ds)
|
|
|
remote = api_by_date.get(ds)
|
|
|
- if date.fromisoformat(ds) < today and (remote is None or 'booking' not in remote):
|
|
|
- local_cmp = [s for s in (local or []) if s != 'booking'] or None
|
|
|
- remote_cmp = [s for s in (remote or []) if s != 'booking'] or None
|
|
|
- else:
|
|
|
- local_cmp, remote_cmp = local, remote
|
|
|
- if local_cmp != remote_cmp:
|
|
|
+ if local != remote:
|
|
|
results.append({'date': date.fromisoformat(ds), 'local': local, 'remote': remote})
|
|
|
return results
|
|
|
|
|
|
@@ -400,6 +405,10 @@ async def _diff_rule_discounts(
|
|
|
|
|
|
Returns {pipeline_name: [{'date', 'local', 'rule'}]}, only pipelines with diffs.
|
|
|
"""
|
|
|
+ start_date = _clamp_future(start_date)
|
|
|
+ if start_date > end_date:
|
|
|
+ return {}
|
|
|
+
|
|
|
disc_cal = Discount()
|
|
|
room_events = await disc_cal.list(start_date, end_date)
|
|
|
|
|
|
@@ -438,6 +447,10 @@ async def _diff_rule_closed(
|
|
|
|
|
|
Returns {pipeline_name: [{'date', 'in_room': bool, 'in_rule': bool}]}, only pipelines with diffs.
|
|
|
"""
|
|
|
+ start_date = _clamp_future(start_date)
|
|
|
+ if start_date > end_date:
|
|
|
+ return {}
|
|
|
+
|
|
|
closed_cal = Closed()
|
|
|
room_events = await closed_cal.list(start_date, end_date)
|
|
|
|
|
|
@@ -477,6 +490,10 @@ async def _diff_rule_prices(
|
|
|
Returns {pipeline_name: [{'date', 'local_base', 'rule_min'}]}, only pipelines with diffs.
|
|
|
As-booked dates are excluded: the booking price is always authoritative.
|
|
|
"""
|
|
|
+ start_date = _clamp_future(start_date)
|
|
|
+ if start_date > end_date:
|
|
|
+ return {}
|
|
|
+
|
|
|
price_events, res_events = await asyncio.gather(
|
|
|
CalPrice().list(start_date, end_date),
|
|
|
Reservation().list(start_date, end_date),
|