|
|
@@ -171,6 +171,7 @@ class _BookingClient(ServiceClientBase):
|
|
|
self._csrf_token = csrf_token
|
|
|
self._lang = lang
|
|
|
self._cache: dict[str, DayInfo] = {}
|
|
|
+ self._rts: dict[str, int] = {} # date -> rooms_to_sell; internal, not exposed on DayInfo
|
|
|
self._months: MonthCache[dict[str, DayInfo]] = MonthCache(
|
|
|
lambda m, y: self._fetch_month_calendar(m, y),
|
|
|
suspect=self._suspect_month,
|
|
|
@@ -200,6 +201,7 @@ class _BookingClient(ServiceClientBase):
|
|
|
|
|
|
def clear_cache(self) -> None:
|
|
|
self._cache.clear()
|
|
|
+ self._rts.clear()
|
|
|
self._months.clear()
|
|
|
|
|
|
def _apply_env(self, env: dict[str, str]) -> None:
|
|
|
@@ -427,8 +429,8 @@ class _BookingClient(ServiceClientBase):
|
|
|
price=round(float(price_str)) if price_str else None,
|
|
|
available=(info.get('hidden', 0) == 0),
|
|
|
booked=(info.get('net_booked', 0) > 0),
|
|
|
- rooms_to_sell=int(info.get('rooms_to_sell') or 0),
|
|
|
)
|
|
|
+ self._rts[d] = int(info.get('rooms_to_sell') or 0)
|
|
|
else:
|
|
|
# Partner availability API: only rate-level dates; status encodes availability
|
|
|
# "restricted" = open, "closed" = unavailable, "soldout" = booked
|
|
|
@@ -440,8 +442,8 @@ class _BookingClient(ServiceClientBase):
|
|
|
price=round(float(price_str)) if price_str else None,
|
|
|
available=(status == 'restricted'),
|
|
|
booked=(status == 'soldout'),
|
|
|
- rooms_to_sell=None,
|
|
|
)
|
|
|
+ self._rts.pop(d, None)
|
|
|
return result
|
|
|
|
|
|
async def _fetch_month_calendar(self, month: int, year: int) -> dict[str, DayInfo]:
|
|
|
@@ -478,6 +480,8 @@ class _BookingClient(ServiceClientBase):
|
|
|
prefix = f'{year}-{month:02d}'
|
|
|
for d in [k for k in self._cache if k.startswith(prefix)]:
|
|
|
del self._cache[d]
|
|
|
+ for d in [k for k in self._rts if k.startswith(prefix)]:
|
|
|
+ del self._rts[d]
|
|
|
|
|
|
async def get_calendar(self, date_from: str, date_to: str) -> dict[str, DayInfo]:
|
|
|
self._check_fresh()
|
|
|
@@ -634,7 +638,7 @@ class _BookingClient(ServiceClientBase):
|
|
|
if _is_past(d):
|
|
|
return
|
|
|
expected_rts = 1 if available else 0
|
|
|
- if (cached := self._cache.get(d)) and cached.available == available and cached.rooms_to_sell == expected_rts:
|
|
|
+ if (cached := self._cache.get(d)) and cached.available == available and self._rts.get(d) == expected_rts:
|
|
|
return
|
|
|
await self._gql_mutate({'input': {
|
|
|
'checkAddingAVToClosedProperty': False,
|
|
|
@@ -654,7 +658,7 @@ class _BookingClient(ServiceClientBase):
|
|
|
await self.set_rooms_to_sell(d, 0)
|
|
|
else:
|
|
|
cal = await self.get_calendar(d, d)
|
|
|
- day = cal.get(d, DayInfo(date=d, price=None, available=True, booked=False, rooms_to_sell=None))
|
|
|
+ day = cal.get(d, DayInfo(date=d, price=None, available=True, booked=False))
|
|
|
await self.set_rooms_to_sell(d, 0 if day.booked else 1)
|
|
|
self.clear_cache()
|
|
|
_log.info('booking set_availability date=%s available=%s', d, available)
|
|
|
@@ -684,11 +688,12 @@ class _BookingClient(ServiceClientBase):
|
|
|
def _rts_issues(self, cal: 'dict[str, DayInfo]', date_from: str, date_to: str) -> list[dict]:
|
|
|
issues = []
|
|
|
for d, day in sorted(cal.items()):
|
|
|
- if not (date_from <= d <= date_to) or day.rooms_to_sell is None:
|
|
|
+ actual_rts = self._rts.get(d)
|
|
|
+ if not (date_from <= d <= date_to) or actual_rts is None:
|
|
|
continue
|
|
|
expected = 0 if (not day.available or day.booked) else 1
|
|
|
- if day.rooms_to_sell != expected:
|
|
|
- issues.append({'date': d, 'actual_rts': day.rooms_to_sell, 'expected_rts': expected})
|
|
|
+ if actual_rts != expected:
|
|
|
+ issues.append({'date': d, 'actual_rts': actual_rts, 'expected_rts': expected})
|
|
|
return issues
|
|
|
|
|
|
async def diff_remote_sync(self, date_from: str, date_to: str) -> list[dict]:
|