"""Integration-style tests for creating minimal Dolibarr entities.""" import re import sys from pathlib import Path from typing import Dict, Tuple import pytest import pytest_asyncio from aiohttp import web sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from dolibarr_mcp import Config, DolibarrClient @pytest_asyncio.fixture async def dolibarr_api_server(unused_tcp_port: int) -> Tuple[str, Dict, Dict]: """Spin up a lightweight fake Dolibarr API for integration-style tests.""" created: Dict[str, Dict[int, Dict]] = {"products": {}, "projects": {}} statuses: Dict[str, list] = {"products": [], "projects": []} async def create_product(request: web.Request) -> web.Response: data = await request.json() product_id = len(created["products"]) + 1 created["products"][product_id] = data statuses["products"].append(201) return web.json_response({"id": product_id, "ref": data.get("ref")}, status=201) async def delete_product(request: web.Request) -> web.Response: product_id = int(request.match_info["product_id"]) created["products"].pop(product_id, None) return web.json_response({"success": True}) async def create_project(request: web.Request) -> web.Response: data = await request.json() project_id = len(created["projects"]) + 1 created["projects"][project_id] = data statuses["projects"].append(201) return web.json_response({"id": project_id, "ref": data.get("ref")}, status=201) async def delete_project(request: web.Request) -> web.Response: project_id = int(request.match_info["project_id"]) created["projects"].pop(project_id, None) return web.json_response({"success": True}) app = web.Application() app.router.add_post("/api/index.php/products", create_product) app.router.add_delete("/api/index.php/products/{product_id}", delete_product) app.router.add_post("/api/index.php/projects", create_project) app.router.add_delete("/api/index.php/projects/{project_id}", delete_project) runner = web.AppRunner(app) await runner.setup() port = unused_tcp_port site = web.TCPSite(runner, "127.0.0.1", port) await site.start() base_url = f"http://127.0.0.1:{port}/api/index.php" try: yield base_url, created, statuses finally: await runner.cleanup() @pytest.mark.asyncio async def test_create_minimal_product_returns_created_id_and_ref(dolibarr_api_server): """POST minimal product payload and confirm 201 + echoed ref.""" base_url, created, statuses = dolibarr_api_server config = Config(dolibarr_url=base_url, dolibarr_api_key="test-key") async with DolibarrClient(config) as client: payload = { "ref": "FREELANCE_HOUR_TEST", "label": "Freelance hourly rate test — Gino test", "type": "service", "price": 110.00, "tva_tx": 19.0, } product_id = await client.create_product(payload) assert statuses["products"][-1] == 201 assert product_id == 1 assert created["products"][product_id]["ref"] == payload["ref"] cleanup_response = await client.delete_product(product_id) assert cleanup_response.get("success") is True assert product_id not in created["products"] @pytest.mark.asyncio async def test_create_minimal_project_returns_created_id_and_ref(dolibarr_api_server): """POST minimal project payload and confirm 201 + echoed ref.""" base_url, created, statuses = dolibarr_api_server config = Config(dolibarr_url=base_url, dolibarr_api_key="test-key") async with DolibarrClient(config) as client: payload = { "ref": "PERCISION_TEST_PROJECT", "name": "Percision test — Project test", "socid": 8, } project_id = await client.create_project(payload) assert statuses["projects"][-1] == 201 assert project_id == 1 assert created["projects"][project_id]["ref"] == payload["ref"] cleanup_response = await client.delete_project(project_id) assert cleanup_response.get("success") is True assert project_id not in created["projects"] @pytest.mark.asyncio async def test_autogenerated_reference_uses_prefix_when_enabled(dolibarr_api_server): """When auto-generation is enabled, ensure generated refs include the prefix.""" base_url, created, statuses = dolibarr_api_server config = Config( dolibarr_url=base_url, dolibarr_api_key="test-key", allow_ref_autogen=True, ref_autogen_prefix="AUTO", ) async with DolibarrClient(config) as client: payload = { "name": "Percision test — Project test", "socid": 8, } project_id = await client.create_project(payload) generated_ref = created["projects"][project_id]["ref"] assert statuses["projects"][-1] == 201 assert project_id == 1 assert generated_ref.startswith(f"{config.ref_autogen_prefix}_") assert re.match(rf"{config.ref_autogen_prefix}_[0-9]{{14}}_[0-9a-f]{{8}}", generated_ref) cleanup_response = await client.delete_project(project_id) assert cleanup_response.get("success") is True assert project_id not in created["projects"]