feat(integrations): add contact sync service

Add bidirectional contact synchronization between WhatsApp Central and Odoo,
including sync endpoints and ContactSyncService.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude AI
2026-01-29 22:26:18 +00:00
parent 4b15abcbfb
commit 95cd70af1f
5 changed files with 141 additions and 3 deletions

View File

@@ -1,6 +1,6 @@
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from app.routers import odoo_router from app.routers import odoo_router, sync_router
app = FastAPI(title="WhatsApp Central - Integrations Service") app = FastAPI(title="WhatsApp Central - Integrations Service")
@@ -13,6 +13,7 @@ app.add_middleware(
) )
app.include_router(odoo_router) app.include_router(odoo_router)
app.include_router(sync_router)
@app.get("/health") @app.get("/health")

View File

@@ -1,3 +1,4 @@
from app.routers.odoo import router as odoo_router from app.routers.odoo import router as odoo_router
from app.routers.sync import router as sync_router
__all__ = ["odoo_router"] __all__ = ["odoo_router", "sync_router"]

View File

@@ -0,0 +1,48 @@
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from typing import Optional
from app.services.sync import ContactSyncService
router = APIRouter(prefix="/api/sync", tags=["sync"])
class SyncContactRequest(BaseModel):
contact_id: str
phone: str
name: Optional[str] = None
email: Optional[str] = None
@router.post("/contact-to-odoo")
async def sync_contact_to_odoo(request: SyncContactRequest):
"""Sync WhatsApp contact to Odoo partner"""
try:
service = ContactSyncService()
partner_id = await service.sync_contact_to_odoo(
contact_id=request.contact_id,
phone=request.phone,
name=request.name,
email=request.email,
)
if partner_id:
return {"success": True, "odoo_partner_id": partner_id}
raise HTTPException(500, "Failed to sync contact")
except Exception as e:
raise HTTPException(500, str(e))
@router.post("/partner-to-contact/{partner_id}")
async def sync_partner_to_contact(partner_id: int):
"""Sync Odoo partner to WhatsApp contact"""
try:
service = ContactSyncService()
contact_id = await service.sync_partner_to_contact(partner_id)
return {
"success": True,
"contact_id": contact_id,
"message": "Contact found" if contact_id else "No matching contact",
}
except Exception as e:
raise HTTPException(500, str(e))

View File

@@ -1,5 +1,6 @@
from app.services.partner import PartnerService from app.services.partner import PartnerService
from app.services.crm import CRMService from app.services.crm import CRMService
from app.services.product import ProductService from app.services.product import ProductService
from app.services.sync import ContactSyncService
__all__ = ["PartnerService", "CRMService", "ProductService"] __all__ = ["PartnerService", "CRMService", "ProductService", "ContactSyncService"]

View File

@@ -0,0 +1,87 @@
from typing import Optional
import httpx
from app.config import get_settings
from app.services.partner import PartnerService
from app.schemas.partner import PartnerCreate
settings = get_settings()
class ContactSyncService:
"""Sync contacts between WhatsApp Central and Odoo"""
def __init__(self):
self.partner_service = PartnerService()
async def sync_contact_to_odoo(
self,
contact_id: str,
phone: str,
name: str = None,
email: str = None,
) -> Optional[int]:
"""
Sync a WhatsApp contact to Odoo.
Returns Odoo partner_id.
"""
# Check if partner exists
partner = self.partner_service.search_by_phone(phone)
if partner:
return partner.id
# Create new partner
data = PartnerCreate(
name=name or phone,
mobile=phone,
email=email,
)
partner_id = self.partner_service.create(data)
# Update contact in API Gateway with odoo_partner_id
await self._update_contact_odoo_id(contact_id, partner_id)
return partner_id
async def _update_contact_odoo_id(self, contact_id: str, odoo_id: int):
"""Update contact's odoo_partner_id in API Gateway"""
try:
async with httpx.AsyncClient() as client:
await client.patch(
f"{settings.API_GATEWAY_URL}/api/internal/contacts/{contact_id}",
json={"odoo_partner_id": odoo_id},
timeout=10,
)
except Exception as e:
print(f"Failed to update contact odoo_id: {e}")
async def sync_partner_to_contact(self, partner_id: int) -> Optional[str]:
"""
Sync Odoo partner to WhatsApp contact.
Returns contact_id if found.
"""
partner = self.partner_service.get_by_id(partner_id)
if not partner.phone and not partner.mobile:
return None
phone = partner.mobile or partner.phone
# Search contact in API Gateway
try:
async with httpx.AsyncClient() as client:
response = await client.get(
f"{settings.API_GATEWAY_URL}/api/internal/contacts/search",
params={"phone": phone},
timeout=10,
)
if response.status_code == 200:
contact = response.json()
if not contact.get("odoo_partner_id"):
await self._update_contact_odoo_id(contact["id"], partner_id)
return contact["id"]
except Exception as e:
print(f"Failed to search contact: {e}")
return None