Integration Architecture and Data Flow

Core Integration Patterns

You must select a primary integration architecture that dictates how data moves between Teamwork and Odoo 18. The most effective pattern uses Odoo as the integration orchestrator. This design leverages Odoo’s Scheduled Actions to execute synchronization scripts at defined intervals. Odoo initiates API calls to the Teamwork API, processes the returned data, and writes it to the appropriate Odoo models. This centralizes your logic within Odoo and simplifies monitoring and error handling. Alternative patterns, like using a separate middleware layer, add complexity but may suit environments with heavier transformation requirements.

The data flow follows a hub-and-spoke model with Odoo as the central hub. For outbound synchronization, Odoo pushes new project data from its sales or project modules to Teamwork. This creates corresponding projects and task lists when certain business events occur. For inbound synchronization, Odoo pulls time entries, task status updates, and project milestones from Teamwork. This bidirectional flow ensures both systems maintain a consistent state. You must implement idempotent operations to handle cases where the same data gets synchronized multiple times without creating duplicates.

Key Data Entities and Relationships

Your integration will focus on four core data entities: projects, tasks, time entries, and users. In Odoo, a project (project.project) links to a sales order or a direct project creation. In Teamwork, a project contains task lists and tasks. The relationship is typically one-to-one, but complex scenarios may require one Odoo project to map to multiple Teamwork projects. Tasks (project.task in Odoo) represent the individual work items. You will map Odoo tasks to Teamwork tasks, preserving hierarchical relationships if subtasks exist.

Time entries present the most complex mapping challenge. Teamwork time logs associate with specific tasks and contain detailed notes and dates. Odoo uses account.analytic.line for timesheet entries, which must link to an analytic account (usually the project itself) and an employee. The integration must transform a Teamwork time entry, created by a user, into an Odoo timesheet line, created by an employee, ensuring the user-to-employee mapping is accurate. User synchronization establishes this critical link, matching Teamwork users to Odoo employees based on email addresses or a custom identifier.

Authentication and API Communication

Teamwork uses API keys for authentication, which you will send as a header in every HTTP request. Your Odoo integration will store this key securely in a configuration parameter. Odoo 18 communicates with Teamwork using Python’s requests library within a custom module. You will construct RESTful API calls to Teamwork’s endpoints for each entity type. For data writing operations back to Odoo, you will use Odoo’s ORM through a custom model method or the external API. This dual-API approach requires robust network connectivity and timeout handling between your Odoo server and both the Teamwork API and your Odoo instance itself.

Step-by-Step Configuration

Prerequisites and Environment Setup

Begin by gathering your access credentials. You need a Teamwork account with administrator privileges to generate an API key. Log into your Teamwork site, navigate to your user profile, and select the “API Keys” section. Generate a new key and copy it to a secure location. For Odoo 18, ensure you have developer mode activated and access to the Odoo shell or a custom module development environment. You need permissions to create scheduled actions and modify the project, sales, and timesheet modules.

Install the necessary Python dependencies on your Odoo server. The integration relies on the requests library for HTTP communication. Activate your Odoo environment and run pip3 install requests to ensure it is available. Verify your Odoo server has a stable outbound internet connection to reach the Teamwork API endpoints. Test this connectivity using a simple Python script from your Odoo server that attempts a GET request to https://yourcompany.teamwork.com/tasks.json. Resolve any firewall or proxy issues before proceeding.

Create a new Odoo custom module to house your integration code. Define a basic module structure with __init__.py, __manifest__.py, and your main model file, such as models/teamwork_integration.py. In your manifest file, declare dependencies on the project, sale, and hr_timesheet modules. This ensures your integration code can access the necessary Odoo models and fields. This modular approach keeps your integration logic organized and separate from core Odoo code, which simplifies maintenance and future upgrades.

Configuring Odoo System Parameters

Store your Teamwork credentials securely using Odoo’s ir.config_parameter model. Create a system parameter through the Odoo interface or via an XML data file in your module. Define parameters for teamwork.api.key and teamwork.company.url. This method keeps sensitive data out of your codebase and allows for easy configuration across different environments (development, staging, production). You can set these values in Odoo under Settings > Technical > System Parameters.

Implement a configuration model to manage integration settings. Create a new Odoo model, teamwork.settings, with fields for the API key, base URL, synchronization interval, and default project templates. This provides a user-friendly interface for administrators to adjust the integration without editing code. You can add boolean flags to enable or disable specific synchronizations, such as time entry imports or project creation. Link this settings model to a menu item in the Odoo configuration section for easy access.

Define the mapping between Odoo companies and Teamwork sites if you operate a multi-company Odoo database. Your integration logic must determine which Teamwork site corresponds to the current Odoo company context. You can extend your settings model to support multiple configurations, each associated with a specific Odoo company. This ensures that data from one company never accidentally synchronizes with another company’s Teamwork site, maintaining strict data segregation.

Establishing the Core Connection Class

Develop a central Python class, TeamworkClient, to handle all API interactions. This class will encapsulate the authentication logic and provide methods for common operations like get_projects(), create_task(), or get_time_entries(). Initialize this class with the parameters from your system settings. The constructor should set up the base API URL and prepare the authentication headers for all subsequent requests.

import requests
import logging

_logger = logging.getLogger(__name__)

class TeamworkClient:
    def __init__(self, base_url, api_key):
        self.base_url = base_url.rstrip('/')
        self.headers = {
            'Authorization': f'Bearer {api_key}',
            'Content-Type': 'application/json'
        }
    
    def _make_request(self, method, endpoint, data=None):
        url = f"{self.base_url}/{endpoint}.json"
        try:
            response = requests.request(method, url, headers=self.headers, json=data, timeout=30)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            _logger.error("Teamwork API request failed: %s", e)
            raise

Implement specific methods for each entity type. For example, the method to fetch projects would call the projects.json endpoint and parse the response. Each method should handle pagination, as the Teamwork API returns a limited number of records per request. Your methods must loop through all pages to retrieve complete data sets. This ensures your synchronization captures all relevant records, not just the most recent ones.

Creating Synchronization Methods

Build separate synchronization methods for each data direction and entity. For importing Teamwork time entries into Odoo, create a method import_teamwork_time_entries(). This method will call the Teamwork API, transform the data into Odoo timesheet line format, and create the records using Odoo’s ORM. Include filters to import only new time entries based on the last synchronization date, which you should store in your integration settings.

Develop a method to create Teamwork projects from Odoo sales orders. This method should trigger when a sales order reaches a “confirmed” state. It will gather the necessary project details from the sales order and its associated lines, then call the Teamwork API to create a new project. You must decide whether to create the project immediately or queue it for batch processing. Implement a callback to update the Odoo sales order with the newly created Teamwork project ID for future reference.

Handle user and employee mapping through a dedicated synchronization method. This method matches Teamwork users to Odoo employees, typically using email address as the correlation key. Create a mapping table in Odoo that stores the Teamwork user ID and the corresponding Odoo employee ID. This mapping becomes crucial for correctly assigning time entries and task ownership. Run this user synchronization before attempting to sync time or task data to establish the necessary relationships.

Configuring Odoo Scheduled Actions

Create scheduled actions in Odoo to automate the synchronization processes. Configure one scheduled action for importing time entries from Teamwork. Set it to run every hour or several times per day, depending on your business needs for up-to-date timesheet data. The action should execute a method in your integration model that calls the import_teamwork_time_entries() function.

Set up another scheduled action for syncing task status updates from Teamwork to Odoo. This can run less frequently, perhaps every few hours, as task completion status may not require real-time synchronization. The action calls a method that fetches tasks modified since the last sync and updates the corresponding Odoo tasks. You can configure these intervals through the Odoo scheduled action interface, specifying the recurrence pattern and the Python code to execute.

For outbound synchronizations, use Odoo’s built-in automation tools instead of scheduled actions. Implement an Odoo server action that triggers when a sales order is confirmed. This action calls your method to create a Teamwork project. This event-driven approach ensures immediate project creation in Teamwork when a deal closes in Odoo, without waiting for the next scheduled run. You maintain tighter coupling between the business event and the resulting project setup.

Data Mapping and Transformation

Project Data Mapping Strategy

Project mapping establishes the foundation of your integration. When creating a Teamwork project from an Odoo sales order, you must transform Odoo’s commercial data into Teamwork’s project structure. Map the Odoo sales order name to the Teamwork project name. Use the sales order client order reference as the Teamwork project description. Set the Teamwork project category based on the Odoo sales team or a custom field on the sales order. This preserves the business context when the project moves to Teamwork.

Handle date mapping with special attention. The Odoo sales order commitment date becomes the Teamwork project start date. The sales order expected date maps to the Teamwork project end date. For budget tracking, extract the total amount from the Odoo sales order and set it as the Teamwork project budget. This enables project managers to monitor progress against the original sales value directly within Teamwork. Include a custom field in the Teamwork project that stores the Odoo sales order ID for bidirectional reference.

For existing Odoo projects that you want to sync with Teamwork, the mapping follows a different pattern. The Odoo project name maps directly to the Teamwork project name. The Odoo project description becomes the Teamwork project overview. The Odoo project manager should map to a Teamwork administrator for the project. You must establish a consistent naming convention to prevent duplicate project creation across the two systems.

Task and Subtask Hierarchy Mapping

Task synchronization requires careful handling of relationships and statuses. Map Odoo tasks to Teamwork tasks, preserving their hierarchical structure if subtasks exist. The Odoo task name becomes the Teamwork task content. The Odoo task description maps to the Teamwork task description field. For assignment, use the user mapping table to find the corresponding Teamwork user ID for the Odoo task assignee. This ensures tasks appear assigned to the correct person in both systems.

Transform task status values between the different systems. Odoo uses a state selection field (e.g., draft, in progress, done), while Teamwork has completion status and progress percentages. Create a mapping logic where an Odoo task marked “done” sets the Teamwork task to 100% complete. An Odoo task “in progress” translates to a Teamwork task that’s started but not completed. You may need to handle additional statuses based on your specific workflow requirements in both platforms.

Manage task dates and dependencies with transformation logic. The Odoo task planned date becomes the Teamwork task start date. The Odoo task date deadline maps to the Teamwork task due date. For task dependencies, you must parse the Odoo task parent-child relationships and recreate them in Teamwork using the task links feature. This maintains the project work breakdown structure across both systems, though complex dependency chains may require simplification due to API limitations.

Time Entry Transformation Logic

Time entry transformation presents the most complex mapping challenge. A Teamwork time entry contains a date, minutes, description, and user reference. You must convert this into an Odoo timesheet line (account.analytic.line) with an account, employee, project, task, and quantity. The transformation process first identifies the correct Odoo employee using your user mapping table. It then finds the corresponding Odoo project and task using stored external IDs.

Convert the time format from minutes to hours for Odoo. Teamwork records time in minutes, but Odoo timesheets use hours. Divide the Teamwork minutes by 60 and round to two decimal places for the Odoo quantity field. Preserve the Teamwork time entry description as the Odoo timesheet line name. Set the Odoo timesheet date to match the Teamwork time entry date. This ensures accurate daily time recording in both systems.

Handle edge cases in time entry mapping. When a Teamwork time entry has no associated task, map it to the general project in Odoo without a specific task. For time entries that describe non-billable work, set the Odoo timesheet line to non-billable based on your business rules. Implement deduplication checks using the Teamwork time entry ID stored in a custom field on the Odoo timesheet line. This prevents importing the same time entry multiple times during subsequent synchronizations.

Error Handling and Resilience

Common API Integration Errors

Teamwork API rate limiting represents a frequent challenge. The API enforces strict limits on the number of requests per minute. Your integration must include rate limit detection from the response headers and implement automatic retry-after logic. When you hit a rate limit, parse the Retry-After header value and pause subsequent requests for that duration. Log these events for monitoring but do not treat them as critical failures that halt the entire synchronization process.

Authentication failures occur when API keys expire or become invalid. Your code should catch 401 Unauthorized responses from the Teamwork API and log a clear error message indicating the need to update the API key. Design the integration to send an email alert to administrators when authentication fails, as this requires immediate intervention. Similarly, handle 403 Forbidden errors that may indicate insufficient permissions for the requested operation, often due to scope changes in the Teamwork project permissions.

Network timeouts and connection errors demand robust handling. The integration between Odoo and Teamwork depends on stable internet connectivity. Implement a retry mechanism with exponential backoff for transient network failures. Configure reasonable timeout values on your API requests to prevent hanging processes. After a defined number of retry attempts, the integration should log the failure and continue with the next synchronization item rather than stopping completely.

Data Validation and Integrity Errors

Data format mismatches cause persistent synchronization issues. Teamwork may return data in an unexpected format, or required fields may contain null values that Odoo rejects. Implement comprehensive data validation before attempting to create or update records in either system. Check for required fields, data types, and field length constraints. When validation fails, log the specific record and error details for troubleshooting, then skip that record while continuing with others.

Reference integrity errors occur when related records do not exist. For example, a time entry references a Taskwork task that doesn’t have a corresponding Odoo task. Your integration must handle these orphaned records by either creating placeholder tasks or skipping the time entries until the task mapping exists. Maintain an error queue for records that fail processing, with options to retry them after resolving the underlying reference issue.

Duplicate record detection prevents data corruption. Implement checks to avoid creating the same project or task in both systems multiple times. Use external identifier fields to store the Teamwork ID in Odoo records and vice versa. Before creating a new record, check if a record with that external ID already exists. For updates, use the external ID to find and modify the existing record rather than creating a new one.

Recovery Procedures and Data Reconciliation

Develop specific recovery procedures for interrupted synchronizations. Store checkpoint information, such as the last successful synchronization timestamp, in your integration settings. If a sync fails mid-process, the next run can resume from the last checkpoint rather than processing all data again. This prevents missed records and reduces the processing load on both systems.

Implement data reconciliation reports to identify synchronization gaps. Create a dashboard that compares key metrics between Odoo and Teamwork, such as project counts, task completion rates, and total hours recorded. Run these comparisons regularly to detect drift between the systems. The reports should highlight discrepancies for manual investigation and correction, helping you maintain long-term data consistency.

Establish a manual intervention process for irreconcilable records. Some data conflicts may require human judgment to resolve. Create a simple interface in Odoo that displays synchronization errors and allows administrators to take corrective action. This might include merging duplicate records, fixing mapping relationships, or forcing a resynchronization of specific projects. This manual override capability ensures you can always restore synchronization even when automated processes fail.

Testing and Validation

Development Environment Testing Strategy

Create a dedicated testing environment that mirrors your production setup. Use a copy of your production Odoo database and a separate Teamwork test site. This isolation prevents test data from affecting your live operations. Populate both systems with sample data that represents your actual business scenarios, including various project types, task structures, and time entry patterns. This comprehensive test bed ensures your integration handles real-world complexity.

Execute tests in a structured sequence, beginning with unit tests for individual components. Test your Teamwork API client class with mock responses to verify it handles various response types correctly. Validate your data transformation functions with sample inputs and expected outputs. These isolated tests help identify logic errors before you integrate the components. Use Python’s unittest framework to automate these tests and run them as part of your deployment process.

Progress to integration tests that verify the complete data flow. Create a test Odoo sales order and trigger the project synchronization to Teamwork. Verify the project appears in Teamwork with the correct mapping of all fields. Then create tasks and time entries in Teamwork and run the import synchronization to Odoo. Check that the records appear in Odoo with proper relationships to projects and employees. Document each test case and its expected outcome for repeatable validation.

Data Synchronization Validation Checklists

Develop a pre-deployment validation checklist for each synchronization direction. For project creation from Odoo to Teamwork, verify that all required fields transfer correctly, the project appears in the proper Teamwork category, and the budget value matches the Odoo sales order amount. Confirm that the Odoo sales order updates with the Teamwork project ID for future reference. Test with different sales order types to ensure consistent behavior.

For time entry import from Teamwork to Odoo, validate that time entries map to the correct Odoo employees, projects, and tasks. Verify the time conversion from minutes to hours calculates accurately. Check that billable status transfers correctly based on your business rules. Confirm that duplicate time entries do not create duplicate Odoo timesheet lines, even when the synchronization runs multiple times. Test with edge cases like time entries without associated tasks.

Create a post-synchronization audit process. After each major synchronization cycle, generate a report that compares record counts between systems. The report should highlight any significant discrepancies for investigation. Implement data quality checks, such as verifying that the total hours imported from Teamwork match the expected values based on the source data. These regular audits ensure ongoing synchronization accuracy and quickly surface any developing issues.

Performance and Load Testing

Assess integration performance under realistic data volumes. Test with project portfolios that match your production scale in terms of the number of projects, tasks, and daily time entries. Measure synchronization duration for each data type and identify any bottlenecks. Pay particular attention to time entry synchronization, as this typically involves the largest data volumes. Ensure the process completes within your required time windows, especially for frequent synchronizations.

Test the integration’s behavior under error conditions. Simulate Teamwork API outages by temporarily blocking network access and verify the integration handles these gracefully without data loss. Test with malformed data responses to ensure proper error logging and continuation of processing. Verify that rate limiting responses from the Teamwork API trigger the appropriate backoff behavior without requiring manual intervention.

Establish performance benchmarks for ongoing monitoring. Record baseline metrics for synchronization duration, API call counts, and data processing rates. Monitor these metrics in production to detect performance degradation over time. Set up alerts for synchronization processes that exceed expected time thresholds or encounter higher-than-normal error rates. This proactive monitoring helps you address performance issues before they impact business operations.

Security Considerations

Authentication and Access Control

Secure API key management forms the foundation of integration security. Store Teamwork API keys in Odoo’s system parameters rather than hardcoding them in your module. Restrict access to these parameters to authorized administrators only. Consider implementing key rotation policies and procedures for regularly updating these credentials. For additional security, you might store encrypted versions of the keys and decrypt them only during actual API communication.

Implement principle of least privilege for API access. The Teamwork API key should have only the necessary permissions for the integration’s intended functions. If the integration only reads time entries and updates task statuses, limit the key to those specific scopes. Avoid using administrator-level API keys unless absolutely necessary. Similarly, in Odoo, ensure the user account executing the synchronization has minimal required permissions to the relevant models.

Secure the communication channels between systems. All API calls to Teamwork must use HTTPS to encrypt data in transit. Verify SSL certificate validity to prevent man-in-the-middle attacks. Within Odoo, protect your custom integration models with appropriate access rights and record rules. This prevents unauthorized users from modifying integration settings or accessing synchronization data outside their permitted scope.

Data Protection and Compliance

Anonymize or pseudonymize test data to protect sensitive information. When using production data for testing, replace personally identifiable information with realistic but fictional data. This practice prevents accidental exposure of customer details or employee information during development and testing phases. Establish clear data handling policies for your integration that align with your organization’s overall security framework.

Address data residency requirements if your Odoo instance and Teamwork site operate in different geographic regions. Understand where each system stores data and ensure this complies with your organizational policies and regulatory obligations. For industries with strict data sovereignty requirements, you may need to configure both systems to use the same geographic region or implement additional encryption for cross-border data transfers.

Implement comprehensive audit logging for all integration activities. Log each synchronization event, including timestamps, record counts, and any errors encountered. This audit trail helps with troubleshooting and provides evidence for compliance purposes. Ensure logs capture sufficient detail to reconstruct data flows while avoiding storage of sensitive information itself. Regularly review these logs for suspicious patterns that might indicate security issues.

Performance Optimization

API Call Efficiency Strategies

Minimize API calls through intelligent batching and filtering. Teamwork’s API supports filtering results by date ranges, which dramatically reduces payload sizes for incremental synchronizations. Instead of fetching all projects every time, query only those modified since your last successful sync. Apply similar filters to tasks and time entries. For time entries, which typically represent the largest data volume, use tight date ranges aligned with your business reporting needs.

Implement strategic caching for reference data. User mappings between Teamwork and Odoo change infrequently, so cache these in memory during synchronization processes rather than querying the database repeatedly. Similarly, cache project mappings to avoid lookups for every task or time entry. Set appropriate cache expiration times to ensure the integration uses fresh data without sacrificing performance. This caching layer can reduce database load and improve synchronization speed.

Optimize payload sizes by selecting only necessary fields. Teamwork API endpoints often return comprehensive object representations with numerous fields. Use field filtering parameters to request only the specific fields your integration requires. This reduces network transfer times and memory usage during processing. Similarly, when writing data to Odoo through the ORM, pass only the fields you need to update rather than complete record representations.

Database and Processing Optimization

Batch database operations to reduce transaction overhead. When creating multiple Odoo records from imported Teamwork data, use the ORM’s create method with a list of dictionaries rather than individual create calls. This allows Odoo to optimize the database inserts as a single operation. Apply the same batching principle when updating existing records. For large data volumes, process records in chunks to prevent memory exhaustion and transaction timeouts.

Tune scheduled action frequency based on business needs. Not all synchronizations require the same urgency. Time entries might need frequent import for accurate timesheet reporting, while project metadata changes less often. Adjust synchronization intervals accordingly—perhaps hourly for time entries but only daily for project and task updates. This balanced approach reduces system load while maintaining data freshness where it matters most.

Monitor and optimize long-running operations. For initial synchronization of historical data, implement a resumable process that handles interruptions gracefully. Use Odoo’s job queue system (if available) to process large synchronization tasks in the background without blocking other operations. Implement progress tracking for these bulk operations so administrators can monitor completion status and estimate remaining time.