Add fetch_category_names to Eviivo, QBook and Mews profiles
- Eviivo: no-dates page fetch returns all room types with data-item-name and
data-rate-plan-name; single request populates the full name catalogue
- QBook: item_name already in /api/pull response; extracted on a dummy date
call; no distinct rate plan names exposed so rate_labels left empty
- Mews: getCalendarData (bookingEngineId field) returns resourceCategories[].name
and rates[].name as {en-US: ...} dicts; both room and rate labels populated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c2e1a9703a
commit
68e8a6883b
3 changed files with 89 additions and 0 deletions
|
|
@ -44,6 +44,30 @@ class EviivoProfile(BaseProfile):
|
||||||
return {"property_slug": m.group(1)}
|
return {"property_slug": m.group(1)}
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
async def fetch_category_names(self, client, params: dict) -> tuple[dict, dict]:
|
||||||
|
slug = params["property_slug"]
|
||||||
|
try:
|
||||||
|
r = await client.get(f"https://via.eviivo.com/{slug}", headers=HEADERS, timeout=20)
|
||||||
|
except Exception:
|
||||||
|
return {}, {}
|
||||||
|
if r.status_code != 200:
|
||||||
|
return {}, {}
|
||||||
|
room_names: dict[str, str] = {}
|
||||||
|
rate_names: dict[str, str] = {}
|
||||||
|
for tag in _TAG_RE.finditer(r.text):
|
||||||
|
attrs = _extract_data_attrs(tag.group(0))
|
||||||
|
room_id = attrs.get("room-type-id", "").strip()
|
||||||
|
if not room_id:
|
||||||
|
continue
|
||||||
|
room_name = attrs.get("item-name", "").strip()
|
||||||
|
rate_plan = attrs.get("rate-plan-name", "").strip()
|
||||||
|
rate_id = f"{room_id}_{_slugify(rate_plan) if rate_plan else 'standard'}"
|
||||||
|
if room_name:
|
||||||
|
room_names[room_id] = room_name
|
||||||
|
if rate_plan:
|
||||||
|
rate_names[rate_id] = rate_plan
|
||||||
|
return room_names, rate_names
|
||||||
|
|
||||||
async def fetch_arrival_dates(self, client, params: dict) -> list[str]:
|
async def fetch_arrival_dates(self, client, params: dict) -> list[str]:
|
||||||
"""Return the next 90 days as ISO date strings starting from tomorrow.
|
"""Return the next 90 days as ISO date strings starting from tomorrow.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,40 @@ class MewsProfile(BaseProfile):
|
||||||
return {"booking_engine_id": m.group(1)}
|
return {"booking_engine_id": m.group(1)}
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
async def fetch_category_names(self, client, params: dict) -> tuple[dict, dict]:
|
||||||
|
if not await _ensure_config(client, params):
|
||||||
|
return {}, {}
|
||||||
|
tz = params.get("_tz", ZoneInfo("Europe/London"))
|
||||||
|
today = date.today()
|
||||||
|
r = await client.post(
|
||||||
|
f"{API_BASE}/services/getCalendarData",
|
||||||
|
json={
|
||||||
|
"bookingEngineId": params["booking_engine_id"],
|
||||||
|
"serviceId": params["service_id"],
|
||||||
|
"startUtc": _midnight_utc(today, tz),
|
||||||
|
"endUtc": _midnight_utc(today + timedelta(days=7), tz),
|
||||||
|
"client": CLIENT,
|
||||||
|
"session": _session(),
|
||||||
|
},
|
||||||
|
headers=HEADERS,
|
||||||
|
timeout=20,
|
||||||
|
)
|
||||||
|
if r.status_code != 200:
|
||||||
|
return {}, {}
|
||||||
|
data = r.json()
|
||||||
|
lang = "en-US"
|
||||||
|
room_names = {
|
||||||
|
cat["id"]: cat["name"].get(lang, cat["id"])
|
||||||
|
for cat in data.get("resourceCategories", [])
|
||||||
|
if "name" in cat
|
||||||
|
}
|
||||||
|
rate_names = {
|
||||||
|
rate["id"]: rate["name"].get(lang, rate["id"])
|
||||||
|
for rate in data.get("rates", [])
|
||||||
|
if "name" in rate
|
||||||
|
}
|
||||||
|
return room_names, rate_names
|
||||||
|
|
||||||
async def fetch_arrival_dates(self, client, params: dict) -> list[str]:
|
async def fetch_arrival_dates(self, client, params: dict) -> list[str]:
|
||||||
if not await _ensure_config(client, params):
|
if not await _ensure_config(client, params):
|
||||||
return []
|
return []
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,37 @@ class QBookProfile(BaseProfile):
|
||||||
dk = unquote(dk_match.group(1)) if dk_match else ""
|
dk = unquote(dk_match.group(1)) if dk_match else ""
|
||||||
return {"hotel_id": hotel_id, "dk": dk}
|
return {"hotel_id": hotel_id, "dk": dk}
|
||||||
|
|
||||||
|
async def fetch_category_names(self, client, params: dict) -> tuple[dict, dict]:
|
||||||
|
hotel_id = params["hotel_id"]
|
||||||
|
dk = params["dk"]
|
||||||
|
from datetime import date, timedelta
|
||||||
|
tomorrow = (date.today() + timedelta(days=1)).isoformat()
|
||||||
|
day_after = (date.today() + timedelta(days=2)).isoformat()
|
||||||
|
try:
|
||||||
|
r = await client.get(
|
||||||
|
"https://web-bookings.hotels.uk.com/api/pull",
|
||||||
|
params={
|
||||||
|
"HotelAvailability": "", "k": _BUNDLE_K,
|
||||||
|
"HotelID": hotel_id, "from": tomorrow, "to": day_after,
|
||||||
|
"json": "", "dk": dk, "Qbook": "",
|
||||||
|
"GHABooking": "", "CookieBooking": "", "COOKIE_HotelID": "",
|
||||||
|
"guests": "", "adultsCheck": "", "childAges": "",
|
||||||
|
"roomId": "", "revised": "",
|
||||||
|
},
|
||||||
|
headers={**HEADERS, "Auth": _build_auth(hotel_id, tomorrow, day_after)},
|
||||||
|
timeout=20,
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
return {}, {}
|
||||||
|
if r.status_code != 200:
|
||||||
|
return {}, {}
|
||||||
|
room_names: dict[str, str] = {}
|
||||||
|
for item_id, item in r.json().get("availability", {}).items():
|
||||||
|
if isinstance(item, dict) and item.get("item_name"):
|
||||||
|
room_names[str(item_id)] = item["item_name"]
|
||||||
|
# QBook has no distinct rate plan names
|
||||||
|
return room_names, {}
|
||||||
|
|
||||||
async def fetch_arrival_dates(self, client, params: dict) -> list[str]:
|
async def fetch_arrival_dates(self, client, params: dict) -> list[str]:
|
||||||
today = date.today()
|
today = date.today()
|
||||||
return [(today + timedelta(days=i)).isoformat() for i in range(1, 91)]
|
return [(today + timedelta(days=i)).isoformat() for i in range(1, 91)]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue