Integration Architecture and Data Flow
The Microsoft Teams and Odoo 18 integration relies on a bidirectional data bridge. This architecture uses webhooks for real-time notifications and scheduled jobs for batch synchronization. The system centers on a custom Odoo module that acts as the integration engine. This module handles authentication, data transformation, and API communication with both platforms.
Microsoft Graph API serves as our gateway to Teams data. We configure change notifications for specific events like new channel messages or created meetings. Odoo 18’s ir.webservice and base.automation frameworks form the core of our inbound data handling. We design listeners for these webhooks that trigger server actions.
Data flows in two primary directions. From Teams to Odoo, we capture events like new chat messages containing specific keywords. These messages create leads in Odoo CRM or log timesheets in project tasks. From Odoo to Teams, we push notifications about record changes. A new sales order posts a summary to a designated Teams channel. A stalled project task sends an alert to the project team.
The Odoo module uses a queueing system for resilience. We implement the queue.job library to process incoming webhook payloads. This design prevents data loss during high-volume periods or temporary Odoo server restarts. Each integration point employs idempotent operations. This ensures duplicate webhook deliveries from Microsoft do not create duplicate records in Odoo.
We structure the data flow around a central mapping model. This model stores the correlation between Teams teams/channels and Odoo models/records. A mapping entry might link the “Sales” team to the Odoo CRM lead model. Another links a “Project Alpha” channel to a specific project task. This configuration drives all automated data routing between the two systems.
Step-by-Step Configuration
Azure App Registration for Graph API Access
Start in the Azure Portal. Navigate to Azure Active Directory and select “App registrations”. Create a new registration. Grant it a name like “Odoo Teams Integration”. Set the supported account types based on your Microsoft 365 tenant. Note the Application (client) ID and Directory (tenant) ID. You need these values for Odoo configuration.
Generate a client secret. Click “Certificates & secrets” and create a new client secret. Set a descriptive description and choose an expiration period. Copy the secret’s value immediately. You cannot retrieve it after you leave the page. Configure API permissions for the Azure app. Add the following Microsoft Graph application permissions: ChannelMessage.Send, Chat.ReadWrite, Channel.ReadBasic.All, and OnlineMeetings.ReadWrite.
Odoo Module Skeleton and Dependencies
Create a new Odoo module named teams_integration. Define its __manifest__.py file. Declare dependencies on mail, crm, project, and queue_job. The queue_job dependency is critical for handling webhooks without timing out.
{
'name': 'Microsoft Teams Integration',
'version': '18.0.1.0.0',
'category': 'Integration',
'depends': ['base', 'mail', 'crm', 'project', 'queue_job'],
'data': [
'security/ir.model.access.csv',
'views/teams_mapping_views.xml',
'views/res_config_settings_views.xml',
],
'application': True,
}
Configuration Model and Settings
We create a central configuration model. This model stores the Azure app credentials and sync parameters. We extend the res.config.settings view to provide a user interface for administrators.
from odoo import models, fields
class TeamsIntegrationConfig(models.Model):
_name = 'teams.integration.config'
_description = 'Teams Integration Configuration'
name = fields.Char(string='Configuration Name', required=True)
tenant_id = fields.Char(string='Azure Tenant ID', required=True)
client_id = fields.Char(string='Client ID', required=True)
client_secret = fields.Char(string='Client Secret', required=True)
webhook_verification_token = fields.Char(string='Webhook Token')
active = fields.Boolean(string='Active', default=True)
Add the configuration fields to res.config.settings using a One2many relation. This allows multiple configuration sets for different environments.
Microsoft Graph Authentication Service
Implement the OAuth2 client credentials flow. This server-to-server flow does not require a user to log in. We create a service class that handles token acquisition and renewal.
import requests
import json
from odoo import models, fields, api
from odoo.exceptions import UserError
class MicrosoftGraphService(models.Model):
_name = 'microsoft.graph.service'
_description = 'Microsoft Graph API Service'
def _get_access_token(self, config):
url = f"https://login.microsoftonline.com/{config.tenant_id}/oauth2/v2.0/token"
data = {
'client_id': config.client_id,
'client_secret': config.client_secret,
'scope': 'https://graph.microsoft.com/.default',
'grant_type': 'client_credentials'
}
response = requests.post(url, data=data)
if response.status_code != 200:
raise UserError(f"Authentication failed: {response.text}")
return response.json().get('access_token')
Webhook Subscription Management
Create a service to manage Teams webhook subscriptions. We subscribe to specific resource types, like chats or channels. The subscription specifies the change types we want to receive.
def create_teams_subscription(self, config, resource, change_type):
access_token = self._get_access_token(config)
url = "https://graph.microsoft.com/v1.0/subscriptions"
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
payload = {
"changeType": change_type,
"notificationUrl": f"https://your-odoo-domain.com/teams/webhook",
"resource": resource,
"expirationDateTime": "2025-12-31T11:00:00.0000000Z",
"clientState": config.webhook_verification_token
}
response = requests.post(url, headers=headers, json=payload)
return response.json()
Odoo Webhook Controller Implementation
Build a webhook controller in Odoo to receive Teams notifications. This controller validates the request and enqueues the payload for processing.
from odoo import http
from odoo.http import request
import json
class TeamsWebhookController(http.Controller):
@http.route('/teams/webhook', type='json', auth='public', methods=['POST'])
def handle_teams_webhook(self):
data = request.jsonrequest
verification_token = request.httprequest.headers.get('Authorization')
# Validate the token against your stored token
config = request.env['teams.integration.config'].search([('webhook_verification_token', '=', verification_token)], limit=1)
if not config:
return {'status': 'unauthorized'}
# Enqueue the job for background processing
request.env['teams.integration.config'].with_delay()._process_webhook_payload(data)
return {'status': 'ok'}
Mapping Interface Configuration
Develop the user interface for mapping Teams entities to Odoo models. We create a tree and form view for the teams.mapping model. This allows administrators to define which Teams activity creates which Odoo record.
<record id="view_teams_mapping_tree" model="ir.ui.view">
<field name="name">teams.mapping.tree</field>
<field name="model">teams.mapping</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="teams_team_id"/>
<field name="teams_channel_id"/>
<field name="odoo_model_id"/>
<field name="active"/>
</tree>
</field>
</record>
Data Mapping and Transformation
Core Data Model Relationships
We design a mapping model that defines the relationship between Teams structure and Odoo records. This model acts as the routing table for all integrated data. Each mapping record specifies a source in Teams and a target in Odoo.
class TeamsMapping(models.Model):
_name = 'teams.mapping'
_description = 'Teams to Odoo Mapping'
name = fields.Char(required=True)
teams_team_id = fields.Char(string='Teams Team ID')
teams_channel_id = fields.Char(string='Teams Channel ID')
teams_chat_id = fields.Char(string='Teams Chat ID')
odoo_model_id = fields.Many2one('ir.model', string='Odoo Model')
odoo_record_id = fields.Integer(string='Odoo Record ID')
field_mapping_line_ids = fields.One2many('teams.field.mapping', 'mapping_id')
active = fields.Boolean(default=True)
Field-Level Mapping System
The field mapping system translates data between Teams API payloads and Odoo model fields. We create a separate model to store these field-to-field relationships. This supports complex transformations and value formatting.
class TeamsFieldMapping(models.Model):
_name = 'teams.field.mapping'
_description = 'Teams to Odoo Field Mapping'
mapping_id = fields.Many2one('teams.mapping', required=True)
teams_field = fields.Char(string='Teams Field Path', required=True)
odoo_field = fields.Char(string='Odoo Field Name', required=True)
transformation_type = fields.Selection([
('direct', 'Direct Copy'),
('template', 'Template'),
('function', 'Python Function')
], default='direct')
transformation_template = fields.Text(string='Transformation Template')
Message to Lead Transformation Logic
When a Teams message creates an Odoo lead, we extract specific data points. We parse the message content for customer names, company information, and requirements. The system uses predefined patterns to identify these elements.
The transformation process follows a multi-step pattern. First, we extract the raw message content and sender information from the webhook payload. Next, we apply regex patterns to identify potential company names and phone numbers. Then, we map these extracted values to the corresponding Odoo lead fields.
def transform_message_to_lead(self, payload, mapping):
message_data = payload['data']
lead_vals = {
'name': self._extract_subject(message_data['body']['content']),
'partner_name': self._extract_company_name(message_data),
'email_from': self._get_sender_email(message_data),
'description': message_data['body']['content'],
'teams_message_id': message_data['id'],
'teams_channel_id': payload['resourceData']['channelId'],
}
return lead_vals
Meeting to Calendar Event Mapping
We sync Teams online meetings to Odoo calendar events. This requires careful timezone conversion and attendee management. The system maps Microsoft’s complex meeting object to Odoo’s event model.
The transformation handles the Teams meeting join URL. We store this as a clickable link in the Odoo event description. We extract participant email addresses from the Teams meeting and create corresponding Odoo event attendees. The system converts UTC timestamps from Microsoft to the user’s local timezone in Odoo.
Project Task Synchronization
Project task updates in Odoo post notifications to linked Teams channels. We map Odoo task fields to adaptive card components in Teams. The system converts task assignment changes, status updates, and deadline modifications into rich Teams messages.
The reverse synchronization also occurs. A user comment in a Teams channel attached to a project creates a task message in Odoo. We maintain user identity mapping between Microsoft 365 accounts and Odoo users. This ensures the correct user receives credit for the message in the Odoo task timeline.
Error Handling and Resilience
Common Microsoft Graph API Errors
The integration encounters specific HTTP status codes from Microsoft Graph. A 401 status indicates an expired or invalid access token. Our system detects this and automatically refreshes the token using the client credentials flow. We implement a retry mechanism with exponential backoff for 429 (rate limit) responses.
We log all Graph API errors with full context for debugging. Each error log includes the request ID Microsoft returns in the response headers. This request ID is essential for troubleshooting with Microsoft support. We design our integration to handle partial failures, such as when some channel messages sync while others fail.
Odoo Validation Error Handling
Data transformation can produce values that violate Odoo model constraints. Our code catches these ValidationError exceptions and routes them to a dedicated error queue. We implement a dead letter queue for records that fail after multiple retry attempts.
For each failed record, we store the original Teams payload and the transformation error. Administrators review these errors through a dedicated Odoo interface. They can correct data issues and reprocess individual records without affecting the entire integration.
Webhook Delivery Guarantees
Microsoft Teams webhooks use a retry mechanism for failed deliveries. Our webhook endpoint returns appropriate HTTP status codes to acknowledge receipt. We design the endpoint to validate the webhook signature before processing. This prevents malicious payloads from entering our system.
We implement idempotent webhook processing. Each webhook includes a unique ID that we track in Odoo. Before processing a webhook, we check if we have already handled this ID. This prevents duplicate record creation from retried webhook deliveries.
Network and Connectivity Failures
Temporary network outages between Odoo and Microsoft Graph API can disrupt synchronization. We use the Odoo queue job system to handle these interruptions. Failed jobs remain in the queue and retry according to a configured schedule.
We implement circuit breaker patterns for external API calls. If Microsoft Graph API becomes unresponsive, our system detects this and stops making requests for a cooling-off period. This prevents overwhelming the external service during its recovery period.
Data Consistency Verification
We build automated consistency checks that run on a schedule. These checks compare record counts between Teams and Odoo for specific mapping rules. The system generates a discrepancy report for administrators when it detects synchronization gaps.
For critical data flows, we implement a repair function. This function identifies missing records in either system and creates synchronization jobs to restore consistency. We design these repairs to handle conflicts where both systems contain different versions of the same business entity.
Testing and Validation
Webhook Simulation Test Suite
We create a comprehensive test suite that simulates Teams webhook payloads. These tests verify our Odoo webhook endpoint processes notifications correctly. We cover various event types: new channel messages, meeting creations, and chat modifications.
Our test cases include edge conditions like malformed JSON, missing required fields, and oversized payloads. We verify the system handles these scenarios without crashing. Each test validates both the HTTP response and the resulting Odoo data changes.
def test_webhook_channel_message_creation(self):
mock_payload = {
"value": [{
"resource": "teams/channel/message",
"changeType": "created",
"resourceData": {
"id": "12345",
"channelId": "test-channel"
}
}]
}
self.url_open('/teams/webhook', data=json.dumps(mock_payload))
# Verify a queue job was created
job_count = self.env['queue.job'].search_count([('name', 'ilike', 'process_teams_webhook')])
self.assertEqual(job_count, 1)
End-to-End Integration Validation
We design multi-step validation scenarios that span both systems. A test creates a message in a Teams channel, then verifies the corresponding Odoo record creation. We measure the complete round-trip time from Teams action to Odoo record availability.
Our validation covers data fidelity. We confirm that all relevant field values transfer correctly between systems. Special attention goes to rich text formatting, date/time values, and user identity mapping. We test with real-world data samples to ensure the transformation logic handles actual business scenarios.
Performance and Load Testing
We assess the integration under realistic load conditions. Our tests measure how the system handles simultaneous webhook deliveries from multiple Teams tenants. We establish performance benchmarks for key operations: message processing, lead creation, and meeting synchronization.
Load tests identify bottlenecks in our queue processing system. We tune the number of concurrent job workers based on these results. We verify that the integration maintains responsive performance during peak business hours when Teams activity is highest.
User Acceptance Testing Framework
We develop a UAT checklist for business teams to validate the integration. This checklist includes real-world tasks like “Mention a customer in channel chat and verify lead creation” and “Schedule a Teams meeting and confirm Odoo calendar sync”.
The UAT process captures feedback on the mapping rules and field transformations. Business users often identify subtle data quality issues that technical tests miss. We incorporate this feedback into refinement cycles before production deployment.
Rollback and Recovery Testing
We verify our ability to pause, resume, or roll back the integration. Tests confirm that we can disable synchronization without data loss. We practice recovery scenarios where the integration fails and must reprocess missed events.
These tests validate our monitoring and alerting configuration. We ensure administrators receive timely notifications when synchronization health metrics exceed defined thresholds. We document the procedures for investigating and resolving common integration problems.
Security Considerations
Authentication and Secret Management
We store Microsoft Graph API credentials securely in Odoo. The client secret uses Odoo’s encrypted fields capability. We implement credential rotation procedures that allow administrators to update client secrets without integration downtime.
Our integration supports the principle of least privilege. The Azure app requests only the specific Graph API permissions it requires. We avoid broad permissions like Group.ReadWrite.All in favor of scoped alternatives. We review these permissions quarterly as Microsoft expands the Graph API.
Webhook Endpoint Security
The public webhook endpoint requires protection against unauthorized access. We implement two verification methods: the Microsoft-specified validation token and a custom authorization header. The endpoint rejects requests that lack valid credentials.
We configure Odoo to log all webhook access attempts. The logs capture source IP addresses, request headers, and payload sizes. We monitor these logs for suspicious patterns that might indicate reconnaissance attacks against our endpoint.
Data Encryption in Transit and at Rest
All communication between Odoo and Microsoft Graph API uses TLS encryption. We enforce TLS 1.2 or higher for all external connections. The integration verifies Microsoft’s SSL certificates to prevent man-in-the-middle attacks.
Sensitive data stored in Odoo, such as message content and user identifiers, benefits from Odoo’s database security. We implement field-level access controls where appropriate. Teams message content that contains customer information receives the same protection as native Odoo data.
Compliance and Data Governance
The integration follows data retention policies configured in Odoo. We design the synchronization to honor Odoo’s record rules and access controls. Teams data maps to Odoo records with proper ownership and sharing settings.
We document the data flow between systems for compliance audits. The documentation identifies what personal data transfers between Teams and Odoo. We provide administrators with tools to audit synchronization history and identify what user actions created which records.
Performance Optimization
API Call Efficiency and Batching
Microsoft Graph API imposes strict rate limits. We optimize our API usage to stay within these limits while maintaining timely synchronization. We implement request batching for operations that create multiple Odoo records from a single Teams payload.
We use Graph API’s $select and $filter query parameters to reduce response payload sizes. Instead of fetching entire user profiles, we request only the fields our integration requires. We design the system to cache frequently accessed reference data like user identities and channel metadata.
Queue Job Optimization
The Odoo queue job system handles our background processing. We tune the number of concurrent job workers based on server capacity and synchronization requirements. We implement priority queues to ensure time-sensitive operations like meeting notifications process before less urgent tasks.
We monitor job execution times and identify slow-performing operations. Long-running jobs undergo optimization to reduce database queries and external API calls. We implement database indexing on the queue job tables to maintain performance as the job history grows.
Database Performance Tuning
The integration creates additional load on the Odoo database. We add indexes to frequently queried fields like teams_message_id and teams_meeting_id. These indexes speed up duplicate checks and relationship lookups.
We analyze query patterns during peak synchronization periods. The system uses read replicas where appropriate to distribute the database load. We implement periodic cleanup of old synchronization logs and temporary data to prevent table bloat.
Caching Strategies for Reference Data
We cache Microsoft Graph API responses that contain relatively static data. Team structures, channel lists, and user directories change infrequently. We implement a time-to-live cache that refreshes this data on a scheduled basis rather than with every synchronization job.
The cache reduces our API consumption and improves synchronization speed. We design cache invalidation triggers for when administrators make structural changes in Teams. This ensures our integration uses current team and channel information without constant API polling.