fix: update Odoo client for v19 compatibility
- Use persistent httpx client to maintain session cookies
- Update endpoint path to /web/dataset/call_kw/{model}/{method}
- Handle auth response as dict (uid extraction)
- Remove kanban_state field (doesn't exist in Odoo 19)
- Add close() method for graceful shutdown
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -73,6 +73,7 @@ async def lifespan(app: FastAPI):
|
|||||||
task = asyncio.create_task(refresh_loop())
|
task = asyncio.create_task(refresh_loop())
|
||||||
yield
|
yield
|
||||||
task.cancel()
|
task.cancel()
|
||||||
|
await odoo_client.close()
|
||||||
|
|
||||||
|
|
||||||
app = FastAPI(title="TV Dashboard API", lifespan=lifespan)
|
app = FastAPI(title="TV Dashboard API", lifespan=lifespan)
|
||||||
|
|||||||
@@ -10,6 +10,16 @@ class OdooClient:
|
|||||||
self.username = username
|
self.username = username
|
||||||
self.password = password
|
self.password = password
|
||||||
self.uid: int | None = None
|
self.uid: int | None = None
|
||||||
|
self._client: httpx.AsyncClient | None = None
|
||||||
|
|
||||||
|
async def _get_client(self) -> httpx.AsyncClient:
|
||||||
|
if self._client is None or self._client.is_closed:
|
||||||
|
self._client = httpx.AsyncClient(timeout=30.0)
|
||||||
|
return self._client
|
||||||
|
|
||||||
|
async def close(self) -> None:
|
||||||
|
if self._client and not self._client.is_closed:
|
||||||
|
await self._client.aclose()
|
||||||
|
|
||||||
async def _jsonrpc(self, endpoint: str, params: dict[str, Any]) -> Any:
|
async def _jsonrpc(self, endpoint: str, params: dict[str, Any]) -> Any:
|
||||||
payload = {
|
payload = {
|
||||||
@@ -18,11 +28,10 @@ class OdooClient:
|
|||||||
"params": params,
|
"params": params,
|
||||||
"id": 1,
|
"id": 1,
|
||||||
}
|
}
|
||||||
async with httpx.AsyncClient() as client:
|
client = await self._get_client()
|
||||||
response = await client.post(
|
response = await client.post(
|
||||||
f"{self.url}{endpoint}",
|
f"{self.url}{endpoint}",
|
||||||
json=payload,
|
json=payload,
|
||||||
timeout=30.0,
|
|
||||||
)
|
)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
result = response.json()
|
result = response.json()
|
||||||
@@ -31,11 +40,15 @@ class OdooClient:
|
|||||||
return result.get("result")
|
return result.get("result")
|
||||||
|
|
||||||
async def authenticate(self) -> int:
|
async def authenticate(self) -> int:
|
||||||
self.uid = await self._jsonrpc("/web/session/authenticate", {
|
result = await self._jsonrpc("/web/session/authenticate", {
|
||||||
"db": self.database,
|
"db": self.database,
|
||||||
"login": self.username,
|
"login": self.username,
|
||||||
"password": self.password,
|
"password": self.password,
|
||||||
})
|
})
|
||||||
|
if isinstance(result, dict):
|
||||||
|
self.uid = result.get("uid")
|
||||||
|
else:
|
||||||
|
self.uid = result
|
||||||
return self.uid
|
return self.uid
|
||||||
|
|
||||||
async def search_read(
|
async def search_read(
|
||||||
@@ -46,7 +59,7 @@ class OdooClient:
|
|||||||
limit: int = 0,
|
limit: int = 0,
|
||||||
order: str = "",
|
order: str = "",
|
||||||
) -> list[dict[str, Any]]:
|
) -> list[dict[str, Any]]:
|
||||||
return await self._jsonrpc("/web/dataset/call_kw", {
|
return await self._jsonrpc(f"/web/dataset/call_kw/{model}/search_read", {
|
||||||
"model": model,
|
"model": model,
|
||||||
"method": "search_read",
|
"method": "search_read",
|
||||||
"args": [domain or []],
|
"args": [domain or []],
|
||||||
@@ -73,7 +86,7 @@ class OdooClient:
|
|||||||
domain=domain,
|
domain=domain,
|
||||||
fields=[
|
fields=[
|
||||||
"name", "project_id", "stage_id", "user_ids",
|
"name", "project_id", "stage_id", "user_ids",
|
||||||
"priority", "date_deadline", "kanban_state",
|
"priority", "date_deadline",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user