Răsfoiți Sursa

keep booked net as float until CalPrice.set rounds it

ZiB 4 luni în urmă
părinte
comite
bb5d5d3771

+ 6 - 5
room_cal/service_api/_airbnb.py

@@ -68,12 +68,13 @@ def _parse_price(s: str) -> float | None:
     return None
 
 
-def _parse_booked_nets(det: dict, check_in: str, check_out: str) -> dict[str, int]:
+def _parse_booked_nets(det: dict, check_in: str, check_out: str) -> dict[str, float]:
   """Return {YYYY-MM-DD: net_dollars} for each night of a reservation.
 
   Uses proportional apportionment: net_i = total_host_net * (list_i / sum(list)).
   Reads PAYMENTINFO_SECTION from stayHostingDetails (rootPlacement).
   Returns {} if the section is missing or the data is malformed.
+  Values are unrounded floats; CalPrice.set rounds via base=round(base).
   """
   sections = det.get('rootPlacement', [])
   pay = next((s for s in sections if s.get('sectionId') == 'PAYMENTINFO_SECTION'), None)
@@ -105,7 +106,7 @@ def _parse_booked_nets(det: dict, check_in: str, check_out: str) -> dict[str, in
   total_weight = sum(weights)
   if total_weight == 0:
     return {}
-  return {d: round(total_net * w / total_weight) for d, w in zip(nights, weights)}
+  return {d: total_net * w / total_weight for d, w in zip(nights, weights)}
 
 
 class AirbnbAuthError(ServiceAuthError):
@@ -136,7 +137,7 @@ class _AirbnbClient:
     self._refresh_task: asyncio.Task | None = None
     self._http = httpx.AsyncClient(timeout=10.0)
     self._detail_cache: dict[str, dict] = {}
-    self._booked_nets: dict[str, int] = {}
+    self._booked_nets: dict[str, float] = {}
 
   @classmethod
   def from_env(cls) -> '_AirbnbClient':
@@ -447,7 +448,7 @@ class _AirbnbClient:
       key=lambda r: r.check_in,
     )
 
-  async def get_booked_nets(self, date_from: str, date_to: str) -> dict[str, int | None]:
+  async def get_booked_nets(self, date_from: str, date_to: str) -> dict[str, float | None]:
     """Return {date: net_dollars} for Airbnb-booked dates in range.
 
     Fetches StayHostingDetailsQuery for each reservation and apportions total
@@ -489,7 +490,7 @@ class _AirbnbClient:
         self._booked_nets.update(_parse_booked_nets(det, ci, co))
 
     await asyncio.gather(*[fetch_nets(code) for code in set(booked_codes.values())])
-    return {d: self._booked_nets.get(d) for d in booked_codes}
+    return {d: self._booked_nets.get(d) for d in booked_codes}  # float | None per date
 
   async def set_price(self, d: str, price: int) -> None:
     price = int(round(price))

+ 2 - 2
room_cal/service_api/client.py

@@ -124,7 +124,7 @@ class ServiceAPI:
       }
     return result
 
-  async def get_booked_nets(self, start_date: date, end_date: date) -> dict[str, dict[str, int | None]]:
+  async def get_booked_nets(self, start_date: date, end_date: date) -> dict[str, dict[str, float | None]]:
     """Return {date_str: {service_key: net}} for booked dates where per-night net is available.
 
     Only services that implement get_booked_nets contribute data; others are absent from the result.
@@ -137,7 +137,7 @@ class ServiceAPI:
       for key, client in self._clients.items()
       if hasattr(client, 'get_booked_nets')
     })
-    result: dict[str, dict[str, int | None]] = {}
+    result: dict[str, dict[str, float | None]] = {}
     for key, nets in per_service.items():
       if nets is None:
         continue

+ 1 - 1
room_cal/service_api/types.py

@@ -12,7 +12,7 @@ class DayInfo:
   available: bool
   booked: bool
   rooms_to_sell: int | None  # Booking.com only; None for Airbnb
-  booked_net: int | None = None  # per-night net from reservation payment data; Airbnb only
+  booked_net: float | None = None  # per-night net from reservation payment data; Airbnb only
 
 
 @dataclass