feat: add Odoo JSON-RPC client with projects, tasks, and calendar methods

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 09:04:21 +00:00
parent 2158dddb09
commit 2421da1d63
2 changed files with 215 additions and 0 deletions

View File

@@ -0,0 +1,124 @@
import json
import pytest
from unittest.mock import AsyncMock, patch, MagicMock
from modules.odoo_client import OdooClient
@pytest.fixture
def odoo():
return OdooClient(
url="http://localhost:8069",
database="test_db",
username="admin",
password="admin",
)
@pytest.mark.asyncio
async def test_authenticate(odoo):
mock_response = MagicMock()
mock_response.json.return_value = {"jsonrpc": "2.0", "result": 2}
mock_response.raise_for_status = MagicMock()
with patch("httpx.AsyncClient.post", new_callable=AsyncMock, return_value=mock_response):
uid = await odoo.authenticate()
assert uid == 2
assert odoo.uid == 2
@pytest.mark.asyncio
async def test_search_read(odoo):
odoo.uid = 2
mock_response = MagicMock()
mock_response.json.return_value = {
"jsonrpc": "2.0",
"result": [
{"id": 1, "name": "Project A"},
{"id": 2, "name": "Project B"},
],
}
mock_response.raise_for_status = MagicMock()
with patch("httpx.AsyncClient.post", new_callable=AsyncMock, return_value=mock_response):
results = await odoo.search_read(
model="project.project",
domain=[("active", "=", True)],
fields=["name"],
)
assert len(results) == 2
assert results[0]["name"] == "Project A"
@pytest.mark.asyncio
async def test_get_projects(odoo):
odoo.uid = 2
mock_response = MagicMock()
mock_response.json.return_value = {
"jsonrpc": "2.0",
"result": [
{"id": 1, "name": "Web App", "task_count": 5},
],
}
mock_response.raise_for_status = MagicMock()
with patch("httpx.AsyncClient.post", new_callable=AsyncMock, return_value=mock_response):
projects = await odoo.get_projects()
assert len(projects) == 1
assert projects[0]["name"] == "Web App"
@pytest.mark.asyncio
async def test_get_tasks(odoo):
odoo.uid = 2
mock_response = MagicMock()
mock_response.json.return_value = {
"jsonrpc": "2.0",
"result": [
{
"id": 1,
"name": "Implement login",
"project_id": [1, "Web App"],
"stage_id": [1, "In Progress"],
"user_ids": [2],
"priority": "1",
"date_deadline": "2026-02-20",
},
],
}
mock_response.raise_for_status = MagicMock()
with patch("httpx.AsyncClient.post", new_callable=AsyncMock, return_value=mock_response):
tasks = await odoo.get_tasks()
assert len(tasks) == 1
assert tasks[0]["name"] == "Implement login"
@pytest.mark.asyncio
async def test_get_calendar_events(odoo):
odoo.uid = 2
mock_response = MagicMock()
mock_response.json.return_value = {
"jsonrpc": "2.0",
"result": [
{
"id": 1,
"name": "Standup",
"start": "2026-02-15 09:00:00",
"stop": "2026-02-15 09:30:00",
"location": "Sala de juntas",
},
],
}
mock_response.raise_for_status = MagicMock()
with patch("httpx.AsyncClient.post", new_callable=AsyncMock, return_value=mock_response):
events = await odoo.get_calendar_events(
date_from="2026-02-15",
date_to="2026-02-22",
)
assert len(events) == 1
assert events[0]["name"] == "Standup"