Explorar el Código

Fix Booking.com client for updated API versions and new calendar response format

- Update apollographql-client-version for availability MFE (EQNeDROb -> GfHKCJeC)
  and messaging MFE (ABJOTMEQ -> EQSXBFLD)
- Update inventory/fetch request body fields to match current browser requests
- Handle new partner availability API response format for future months: when
  room-level dates are absent, parse availability from rate-level status field
  ("restricted" = open, "closed" = unavailable, "soldout" = booked)
ZiB hace 4 meses
padre
commit
437cdb31f9
Se han modificado 1 ficheros con 31 adiciones y 14 borrados
  1. 31 14
      room_cal/service_api/_booking.py

+ 31 - 14
room_cal/service_api/_booking.py

@@ -329,7 +329,7 @@ class _BookingClient:
       'X-Booking-Pageview-ID': _page_view_id(),
       'X-Booking-Pageview-ID': _page_view_id(),
       'x-booking-csrf-token': 'undefined',
       'x-booking-csrf-token': 'undefined',
       'apollographql-client-name': 'b-partner-availability-extranet-mfe',
       'apollographql-client-name': 'b-partner-availability-extranet-mfe',
-      'apollographql-client-version': 'EQNeDROb',
+      'apollographql-client-version': 'GfHKCJeC',
       'x-envoy-expected-rq-timeout-ms': '60000',
       'x-envoy-expected-rq-timeout-ms': '60000',
       'x-booking-timeout-budget-ms': '60000',
       'x-booking-timeout-budget-ms': '60000',
       'X-Booking-Topic': 'capla_browser_b-partner-availability-extranet-mfe',
       'X-Booking-Topic': 'capla_browser_b-partner-availability-extranet-mfe',
@@ -353,7 +353,7 @@ class _BookingClient:
       'x-booking-csrf-token': 'undefined',
       'x-booking-csrf-token': 'undefined',
       'X-Booking-Topic': 'capla_browser_b-partner-messaging-extranet-mfe',
       'X-Booking-Topic': 'capla_browser_b-partner-messaging-extranet-mfe',
       'apollographql-client-name': 'b-partner-messaging-extranet-mfe',
       'apollographql-client-name': 'b-partner-messaging-extranet-mfe',
-      'apollographql-client-version': 'ABJOTMEQ',
+      'apollographql-client-version': 'EQSXBFLD',
       'Cookie': self._cookies,
       'Cookie': self._cookies,
     }
     }
 
 
@@ -449,15 +449,31 @@ class _BookingClient:
     room_data = hotel_data.get('rooms', {}).get(str(self._room_id), {})
     room_data = hotel_data.get('rooms', {}).get(str(self._room_id), {})
     rate_dates = room_data.get('rates', {}).get(str(self._rate_id), {}).get('dates', {})
     rate_dates = room_data.get('rates', {}).get(str(self._rate_id), {}).get('dates', {})
     result: dict[str, DayInfo] = {}
     result: dict[str, DayInfo] = {}
-    for d, info in room_data.get('dates', {}).items():
-      price_str = rate_dates.get(d, {}).get('price', {}).get('2')
-      result[d] = DayInfo(
-        date=d,
-        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=info.get('rooms_to_sell', 0),
-      )
+    room_level_dates = room_data.get('dates', {})
+    if room_level_dates:
+      # Legacy backend: room-level dates include hidden/net_booked/rooms_to_sell
+      for d, info in room_level_dates.items():
+        price_str = rate_dates.get(d, {}).get('price', {}).get('2')
+        result[d] = DayInfo(
+          date=d,
+          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=info.get('rooms_to_sell', 0),
+        )
+    else:
+      # Partner availability API: only rate-level dates; status encodes availability
+      # "restricted" = open, "closed" = unavailable, "soldout" = booked
+      for d, rate_info in rate_dates.items():
+        price_str = rate_info.get('price', {}).get('2')
+        status = rate_info.get('status', '')
+        result[d] = DayInfo(
+          date=d,
+          price=round(float(price_str)) if price_str else None,
+          available=(status == 'restricted'),
+          booked=(status == 'soldout'),
+          rooms_to_sell=None,
+        )
     return result
     return result
 
 
   async def _fetch_month_calendar(self, month: int, year: int) -> dict[str, DayInfo]:
   async def _fetch_month_calendar(self, month: int, year: int) -> dict[str, DayInfo]:
@@ -471,12 +487,13 @@ class _BookingClient:
         'fields': ['rooms', 'policygroups'],
         'fields': ['rooms', 'policygroups'],
         'rooms': {
         'rooms': {
           'id': [self._room_id],
           'id': [self._room_id],
-          'fields': ['status', 'rooms_to_sell', 'rates', 'nr_rooms', 'net_booked', 'num_guests'],
-          'rates': {'fields': ['price', 'status', 'rooms_to_sell', 'name']},
+          'fields': ['status', 'rooms_to_sell', 'permissions', 'rates', 'nr_rooms', 'net_booked', 'num_guests'],
+          'rates': {'fields': ['permissions', 'price', 'restrictions', 'status', 'rooms_to_sell',
+                               'policygroup_id', 'policy_overrides', 'default_policygroup_id', 'name']},
         },
         },
         'policy': {'fields': ['info']},
         'policy': {'fields': ['info']},
       },
       },
-      'post_process_data_plugins': ['format_price', 'multi_units_check', 'last_update'],
+      'post_process_data_plugins': ['format_price', 'multi_units_check', 'last_update', 'check_dynamic_restrictions'],
     }
     }
     raw = await self._multipart_post(
     raw = await self._multipart_post(
       f'{_BASE}/fresa/extranet/inventory/fetch', self._monthly_referer(), body
       f'{_BASE}/fresa/extranet/inventory/fetch', self._monthly_referer(), body