CRM migration
Field-level mapping, validation, and rollback between CRM Service and Odoo CRM. We move data and schema; workflows are rebuilt natively in Odoo CRM.
CRM Service
Source
Odoo CRM
Destination
Compatibility
12 of 15
objects map 1:1 between CRM Service and Odoo CRM.
Complexity
BStandard
Timeline
4-6 weeks
Overview
Moving from CRM Service to Odoo CRM is a data model consolidation, not a simple record copy. CRM Service maintains separate Account and Contact objects with a many-to-one relationship; Odoo CRM uses res.partner as a unified contact-and-company record with a commercial partner flag for organizations and a contact flag for people. We resolve that structural difference during scoping by creating Odoo Partners in two passes: first as organizations (with commercial_partner_id set to self), then as contacts linked to the organization. Custom fields from CRM Service migrate as Odoo column definitions installed via a custom module before data load. Workflow Rules, Process Builder flows, and Approval Processes do not migrate; we deliver a written automation inventory for Odoo's Action Rules and Studio automations to be rebuilt post-migration. API extraction from CRM Service uses the Bulk API at Enterprise and above, with REST API chunking for Professional tier, and the data loads into Odoo via the xmlrpc interface with partner-resolution sequencing.
Every standard and custom field arrives verified.
AI proposes the map; you confirm before any record moves.
Parent–child, lookups, and ownership stay linked.
Calls, emails, meetings — with original timestamps.
Documents, uploads, and inline notes move with the record.
Why teams make this switch
Leaving
What's pushing teams away
Choosing
What's pulling them in
Object mapping
Each row shows how a CRM Service object lands in Odoo CRM, including any object-level transformations, lookup resolution, or schema-design dependencies.
Typical mapping — final map is confirmed during the sample migration step.
CRM Service
Account
Odoo CRM
res.partner (organization)
1:1CRM Service Accounts map to Odoo res.partner records where is_company = True. We extract Account.Name as partner name, Account.BillingAddress as address fields, Account.Industry as a custom selection field, and Account.AnnualRevenue as a float field. The commercial_partner_id on the created partner record points to itself (self) marking it as the top-level organization. Account is created first so that Contact import can resolve the parent partner reference immediately.
CRM Service
Contact
Odoo CRM
res.partner (contact)
1:1CRM Service Contacts map to Odoo res.partner records where is_company = False and parent_id = the mapped Account. We extract Contact.FirstName and Contact.LastName concatenated into partner name, Contact.Email as email, Contact.Phone as phone, Contact.Title as function/title. The parent_id field links the contact to its organization partner record. Contacts without an Account are created as individual partners (is_company = False, parent_id = null) and flagged for manual review.
CRM Service
Opportunity
Odoo CRM
crm.lead (type = opportunity)
1:1CRM Service Opportunities map to Odoo crm.lead with type = 'opportunity'. We extract Opportunity.Name as lead name, StageName as stage_id (mapped to Odoo stage sequence), Amount as planned_revenue, CloseDate as date_deadline, Probability as odoo_probability (custom float field), and Owner as user_id via email match to Odoo res.users. The partner_id field links the opportunity to the mapped Account partner record.
CRM Service
Lead
Odoo CRM
crm.lead (type = lead)
1:1CRM Service Leads map to Odoo crm.lead with type = 'lead'. Where the destination Odoo instance has the Lead Management module installed (standard on CRM app), leads are tracked as separate crm.lead records until converted to opportunities. We preserve LeadStatus as a custom selection field on the lead. Lead score or rating migrates to priority field. Leads with a CompanyName are created with is_company = True on the linked partner; those without are attached as contacts to the company if one is found by domain match.
CRM Service
Opportunity Stage
Odoo CRM
crm.stage
lossyCRM Service Opportunity stages map to Odoo crm.stage records within the appropriate crm.team sequence. We create stages in the same order as the source, preserving the probability percentage (rounded to nearest integer) and won/lost flags. Stage names are mapped by sequence position rather than by name string because stage names are org-specific in CRM Service.
CRM Service
Product2
Odoo CRM
product.product
1:1CRM Service Products map to Odoo product.product records. We extract Product2.Name as name, ProductCode as default_code, and Description as description. A corresponding product.template record is also created. If the CRM Service product has a standard price, it is set on the template.
CRM Service
OpportunityLineItem
Odoo CRM
sale.order.line
lossyCRM Service Line Items are not directly migratable as standalone records in Odoo because Odoo models line items in the context of a sale.order. We map line items to crm.lead optional lines if Odoo CRM is used without the Sale app. If the customer installs the Sale app during migration, line items are migrated as draft sale.order.line records linked to a draft sale.order record created per Opportunity.
CRM Service
Campaign
Odoo CRM
crm.tag or utm.campaign
lossyCRM Service Campaigns map to Odoo utm.campaign records if the Marketing app is installed. Campaign member responses (Responded, Sent) are preserved as crm.tag values on the linked leads and opportunities. If the Marketing app is not installed, campaign names are stored as crm.tag records and applied to relevant crm.lead records.
CRM Service
Task
Odoo CRM
mail.activity
1:1CRM Service Tasks migrate to Odoo mail.activity records linked to the target res.partner or crm.lead. We extract Task.Subject as activity title, Task.Status as state (done vs open), Task.ActivityDate as date_deadline, Task.Priority as priority, and Task.Description as note. Completed tasks become activities with activity_type_id = 'mail.mail_activity_data_meeting' or a configured type; open tasks become planned activities. Owner resolution is via email match to res.users.
CRM Service
Event
Odoo CRM
calendar.event
1:1CRM Service Events migrate to Odoo calendar.event records. We extract Event.Subject as name, Event.StartDateTime as start, Event.EndDateTime as stop, Event.Location as location, and Event.IsAllDayEvent as allday. Attendees (EventWho) are resolved to res.partner records and added as calendar.attendee records. The linked WhatId (Account, Contact, or Opportunity) is mapped to the event's res_model and res_id.
CRM Service
EmailMessage
Odoo CRM
mail.message
1:1CRM Service EmailMessage records migrate to Odoo mail.message records on the relevant res.partner (Contacts and Accounts) and crm.lead. Email body and subject migrate as message_body and subject fields. The From and To addresses are resolved to res.partner records where possible; raw email addresses are stored as a fallback. HasAttachment migrates as a flag for manual file attachment review.
CRM Service
Note (ContentNote)
Odoo CRM
mail.message (note subtype)
1:1CRM Service Notes migrate as Odoo mail.message records with subtype = 'note' on the parent record (Contact, Account, Opportunity). The note body transfers as plain text. Notes attached to multiple records in CRM Service are migrated to the primary parent and flagged as duplicates for manual review in Odoo.
CRM Service
Custom Object (__c)
Odoo CRM
Custom model (ir.model)
1:1CRM Service custom objects are migrated to Odoo custom models created via a custom module. We generate an ir.model entry, create the corresponding database table, and define fields via ir.model.fields. Lookup relationships to standard objects (Account, Contact, Opportunity) map to Odoo many2one fields pointing to res.partner or crm.lead. The Odoo module is installed in the destination database before any data is loaded. Custom object migration requires Odoo Community or Odoo.sh; Odoo Online SaaS does not allow custom module installation.
CRM Service
User
Odoo CRM
res.users
1:1CRM Service Users are not migrated as records but resolved as references during migration. We extract all OwnerId values from Opportunities, Tasks, and Events and map them by email to existing Odoo res.users. Inactive CRM Service users without an Odoo counterpart are assigned to a migration placeholder user for admin reconciliation.
CRM Service
Attachment
Odoo CRM
ir.attachment
1:1CRM Service Attachments (ContentDocument and Attachment objects) are exported to a staging directory with their parent record reference. We import them as Odoo ir.attachment records linked via res_model and res_id to the migrated parent record (res.partner, crm.lead). File size limits in Odoo are set by the hosting configuration; large files are flagged for manual handoff if they exceed the configured limit.
| CRM Service | Odoo CRM | Compatibility | |
|---|---|---|---|
| Account | res.partner (organization)1:1 | Fully supported | |
| Contact | res.partner (contact)1:1 | Fully supported | |
| Opportunity | crm.lead (type = opportunity)1:1 | Fully supported | |
| Lead | crm.lead (type = lead)1:1 | Fully supported | |
| Opportunity Stage | crm.stagelossy | Fully supported | |
| Product2 | product.product1:1 | Fully supported | |
| OpportunityLineItem | sale.order.linelossy | Fully supported | |
| Campaign | crm.tag or utm.campaignlossy | Fully supported | |
| Task | mail.activity1:1 | Fully supported | |
| Event | calendar.event1:1 | Fully supported | |
| EmailMessage | mail.message1:1 | Fully supported | |
| Note (ContentNote) | mail.message (note subtype)1:1 | Fully supported | |
| Custom Object (__c) | Custom model (ir.model)1:1 | Fully supported | |
| User | res.users1:1 | Fully supported | |
| Attachment | ir.attachment1:1 | Fully supported |
Gotchas + challenges
Platform-specific issues from each side, plus the pair-specific challenges that don't show up on either platform's page on its own.
CRM Service gotchas
API rate limits vary by edition without public documentation
Data Export frequency limited by edition tier
Custom object __c suffix causes field name mismatches in exports
Automations and flows do not migrate between platforms
Multi-select picklist values may exceed destination field limits
Odoo CRM gotchas
Odoo.sh version gating blocks assisted migrations from trial
Enterprise modules fail to install on Community after database restore
Custom module view inheritance breaks between Odoo major versions
Custom fields risk losing their application context on Community
API access for Community is gated behind the Custom Plan
Pair-specific challenges
Migration approach
Discovery and Odoo edition selection
We audit the source CRM Service org across edition (Starter through Einstein 1), active custom objects, custom fields, pipeline count, active Workflow Rules and Flows, engagement volume (Task, Event, EmailMessage counts), and Attachment file size totals. We pair this with an Odoo destination audit: whether the target is Odoo Online (SaaS), Odoo.sh, or self-hosted Community/Enterprise, and which Odoo apps are installed (CRM, Sale, Timesheets, Project). The discovery output is a written migration scope document and an Odoo app recommendation. Custom object migration requires Odoo Community or Odoo.sh; Odoo Online SaaS cannot accept custom module installations.
Custom module development and Odoo schema provisioning
We develop a custom Odoo module that defines all migrated custom fields as Python field definitions (ir.model and ir.model.fields entries) before any data is loaded. The module is installed in the destination Odoo database. We also create the Odoo pipeline stages (crm.stage records) matching the CRM Service Opportunity stage sequence and probabilities, and configure crm.team records if the source uses multiple Salesforce sales territories or queues.
Data extraction, audit, and cleansing
We extract CRM Service data via Bulk API (Enterprise and above) or REST with chunking for Professional tier. The extraction covers Accounts, Contacts, Leads, Opportunities, Products, Campaigns, Tasks, Events, EmailMessages, Notes, and any custom objects. We run a data audit identifying duplicate records, missing required fields, inactive owners, and records with no activity history. We clean duplicates using a probabilistic match on name and email, and flag records with missing critical fields (Account without name, Contact without email) for the customer's admin to resolve before migration.
Partner resolution and two-pass import sequencing
We import Odoo res.partner records in two passes: first all Accounts as organizations (is_company = True, parent_id = null), then all Contacts as contacts (is_company = False, parent_id = mapped Account). CRM Service Opportunities and Leads migrate to crm.lead with type='opportunity' and type='lead' respectively, linking to the resolved partner_id. This two-pass approach is the critical sequencing step that prevents orphaned Contact records. Owner resolution (CRM Service OwnerId to Odoo user_id) happens by email match against res.users.
Sandbox migration and validation
We run a full migration into an Odoo test database (a cloned Odoo.sh branch or a duplicate self-hosted database). The customer's CRM lead reconciles record counts, spot-checks 25-50 records against the CRM Service source, and verifies pipeline stage mapping. Any field mapping corrections, custom field omissions, or stage probability adjustments happen in the test environment before production migration. We do not run production migration without passing sandbox validation first.
Production migration and cutover
We freeze CRM Service writes during cutover, run a final delta extraction for any records modified during the migration window, then execute production migration in dependency order: custom module installation, crm.stage configuration, res.partner organizations, res.partner contacts, crm.lead opportunities and leads, product.product, mail.activity, calendar.event, mail.message, ir.attachment. Each phase emits a reconciliation report. We enable Odoo CRM as the system of record and deliver the Workflow and Flow inventory document for the customer's admin or Odoo partner to rebuild. We do not rebuild CRM Service automations inside the migration scope; that is a separate engagement.
Platform deep dives
CRM Service
Source
Strengths
Weaknesses
Odoo CRM
Destination
Strengths
Weaknesses
Complexity grading
Standard CRM migration. 3 of 8 objects need a mapping; the rest are 1:1.
Overall complexity
Standard migration
Derived from compatibility, mapping clarity, API constraints, and data volume across CRM Service and Odoo CRM.
Object compatibility
3 of 8 objects need a mapping; the rest are 1:1.
Field mapping clarity
Field mapping is derived from defaults — final spec confirmed during the sample migration.
Timeline complexity
8-object category — typical timelines run 2–7 days end-to-end.
API constraints
CRM Service: Varies by edition and license type; not publicly documented with specific numbers.
Data volume sensitivity
CRM Service exposes a bulk API — large-volume migrations stream efficiently.
Estimator
Rule-based pricing — no per-record fees, no manual quotes. Migrations over 2M records are scoped individually.
Step 1
Pick a category, then your source and destination platforms.
Category
FAQ
Answers to the questions buyers ask most during CRM Service to Odoo CRM migration scoping. Not seeing yours? Book a call.
Walk through your CRM Service to Odoo CRM migration with a real engineer — 30 minutes, free, written quote within 24 hours.
Book a free 30 minute consultationAdjacent paths
Other ways to leave CRM Service
Other ways to arrive at Odoo CRM
Ready when you are
Tell us record counts and timeline. We'll come back with a written quote inside 1 business day — no commitment, no sales pitch.