CRM migration
Field-level mapping, validation, and rollback between Odoo Field Service and Twenty CRM. We move data and schema; workflows are rebuilt natively in Twenty CRM.
Odoo Field Service
Source
Twenty CRM
Destination
Compatibility
11 of 12
objects map 1:1 between Odoo Field Service and Twenty CRM.
Complexity
BStandard
Timeline
48–72 hours
Overview
Odoo Field Service runs on Odoo's unified res.partner model — contacts and companies live in the same table — and its field service module (fsm.order, fsm.location, fsm.worker, fsm.tag) is an OCA-maintained add-on layered on top of the CRM, Project, and Inventory apps. Twenty CRM uses a conventional CRM object model: People for contacts, Companies for accounts, and Opportunities for pipeline deals, with a native Tasks object for work items. The migration must split Odoo's res.partner into separate People and Company records in Twenty, map fsm.order records to a Twenty custom object (field_service_order) or Tasks depending on your operational model, and convert crm.lead stages into Twenty Opportunities stage values via a value-by-value pick-list map. FlitStack AI sequences the migration as: Companies first (because Twenty's People requires a companyId relation), then People (with their partner_id → companyId link resolved), then Opportunities (with crm.lead → Opportunity mapping and stage value mapping), then field service orders, then attachments and notes. Owner resolution happens by email match against Twenty workspace members. We do not migrate Odoo workflows, Odoo automation rules, or Odoo Studio custom views — those require a manual rebuild using Twenty's workflow builder or the REST/GraphQL API. The API ingestion path for large record sets uses Twenty's REST endpoints with pagination; bulk CSV import is used for validation batches.
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 Odoo Field Service object lands in Twenty CRM, including any object-level transformations, lookup resolution, or schema-design dependencies.
Typical mapping — final map is confirmed during the sample migration step.
Odoo Field Service
res.partner (type=contact)
Twenty CRM
People
1:1Odoo's res.partner with partner_type='contact' maps directly to Twenty People. The email, phone, address, and job_title fields migrate as standard Twenty People fields. The res.partner.id is preserved as source_system_id__c for delta-run deduplication. This mapping requires the Company records (res.partner type=company) to exist in Twenty first so the companyId relation can resolve.
Odoo Field Service
res.partner (type=company)
Twenty CRM
Companies
1:1Odoo's res.partner with partner_type='company' maps to Twenty Companies. Company name, website, street/city/state/country fields migrate directly. The Odoo parent_id hierarchy (parent/child company relationships) is preserved by mapping parent_id to Twenty's companyId self-relation field. Multi-company Odoo setups map to separate Twenty workspace Companies records.
Odoo Field Service
crm.lead (stage: new / qualified / proposition)
Twenty CRM
Opportunities
1:1Odoo's crm.lead for active pipeline stages (new, qualified, proposition) maps to Twenty Opportunities. The expected_revenue field migrates to amount (currency field). Odoo's crm.stage names (new, qualified, etc.) are mapped via a value map to Twenty's opportunity stageName options. The lead's partner_id is resolved to the People record already migrated.
Odoo Field Service
crm.lead (stage: won / lost)
Twenty CRM
Opportunities (closed)
1:1Won and lost crm.lead records migrate to Twenty Opportunities with stageName set to the corresponding closed stage. Odoo's won/lost stage probability values are mapped value-by-value. Lost reasons stored in Odoo's lost_reason_id field migrate as a custom text field (lost_reason__c) for audit continuity.
Odoo Field Service
fsm.order
Twenty CRM
field_service_order (custom object)
1:1Odoo fsm.order has no native equivalent in Twenty. We create a custom object called 'field_service_order' in Twenty's data model with custom fields for: stage (fsm.stage.name), location_address (fsm.location.partner_id display name + street), scheduled_date (scheduled_date_start), assigned_worker (assigned_to user email match), and tags. The fsm.order.id is stored as source_system_id__c.
Odoo Field Service
fsm.location
Twenty CRM
Companies
many:1Odoo fsm.location records (service site addresses) are merged into the Twenty Companies object. The location name + address fields populate the Company name and address fields. If the location has a related partner_id (customer), we link it to that Company record. Locations without a customer link create standalone Company records in Twenty.
Odoo Field Service
project.task (from Project app linked to fsm)
Twenty CRM
Tasks
1:1Odoo Project tasks linked to fsm.order migrate as Twenty Tasks. The task name, description, planned_date_begin/end, user_id (owner), and stage_id (stage name) map directly. Tasks linked to a fsm.order carry the source fsm.order ID in a custom field (source_fsm_order_id__c) for traceability back to the field service order.
Odoo Field Service
ir.attachment
Twenty CRM
Notes / file import
1:1Odoo file attachments (ir.attachment records linked to res.partner, crm.lead, or fsm.order) are downloaded and re-imported to Twenty. Files attached to People or Companies become Twenty Notes with the attachment content. Large binary files (e.g., signed PDFs from fsm.order worksheets) are stored with a URL reference to the destination storage.
Odoo Field Service
res.users (salesperson / field worker)
Twenty CRM
WorkspaceMember (Twenty users)
1:1Odoo res.users records with active CRM or Field Service access are matched to Twenty workspace members by email address. Unmatched Odoo users (e.g., inactive technicians no longer in the system) are flagged and assigned to a fallback owner. The match is used to resolve owner_id on crm.lead and user_id on fsm.order during migration.
Odoo Field Service
res.partner.bank
Twenty CRM
Custom field on Companies
1:1Odoo bank details on res.partner (res.partner.bank records) have no native equivalent in Twenty's Company object. They are migrated as a custom multi-text field (bank_details__c) containing the account number, bank name, and IBAN as a formatted string. This is a reference-only preservation — payment processing is handled outside Twenty CRM.
Odoo Field Service
crm.lead / res.partner custom fields (x_*, ir.model.fields)
Twenty CRM
Custom fields on People / Opportunities
1:1Any Odoo custom fields added via Odoo Studio or ir.model.fields on crm.lead or res.partner are migrated as Twenty custom fields on People or Opportunities. The field type is inferred from Odoo's field ttype (char→text, integer→number, many2one→relation, selection→select). Fields with no equivalent in Twenty become custom text fields for reference.
Odoo Field Service
fsm.tag
Twenty CRM
Custom multi-select field on field_service_order
1:1Odoo fsm.tag records (name, color) migrate as a multi-select custom field (service_tags__c) on the field_service_order custom object. Tag names are preserved as options; tag colors are not migratable since Twenty multi-select fields use plain text values. Tags are de-duplicated (same name = one option).
| Odoo Field Service | Twenty CRM | Compatibility | |
|---|---|---|---|
| res.partner (type=contact) | People1:1 | Fully supported | |
| res.partner (type=company) | Companies1:1 | Fully supported | |
| crm.lead (stage: new / qualified / proposition) | Opportunities1:1 | Fully supported | |
| crm.lead (stage: won / lost) | Opportunities (closed)1:1 | Fully supported | |
| fsm.order | field_service_order (custom object)1:1 | Fully supported | |
| fsm.location | Companiesmany:1 | Fully supported | |
| project.task (from Project app linked to fsm) | Tasks1:1 | Fully supported | |
| ir.attachment | Notes / file import1:1 | Fully supported | |
| res.users (salesperson / field worker) | WorkspaceMember (Twenty users)1:1 | Fully supported | |
| res.partner.bank | Custom field on Companies1:1 | Fully supported | |
| crm.lead / res.partner custom fields (x_*, ir.model.fields) | Custom fields on People / Opportunities1:1 | Fully supported | |
| fsm.tag | Custom multi-select field on field_service_order1: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.
Odoo Field Service gotchas
Database version upgrade is not a direct restore
Custom fields use x_ column naming that can collide
ir.attachment binaries can exceed API upload limits
Chatter messages use HTML that requires sanitization
Twenty CRM gotchas
Import order is enforced and critical
Export limited to 20,000 records and visible columns only
Soft-deleted records count toward uniqueness and trigger restores
API rate limits cap at 200 req/min on Organization tier
No native email sequences — follow-up cadences require external tools
Pair-specific challenges
Migration approach
Discover Odoo data model and plan Twenty schema
FlitStack AI connects to your Odoo instance via XML-RPC or the Odoo REST API (external API module) and inventories all res.partner records, crm.lead records, fsm.order records, and any custom fields registered in ir.model.fields. We simultaneously review your Twenty workspace and create a custom object (field_service_order) with all required custom fields identified in the Odoo audit. The plan names every custom field to be added, every stage value to be configured, and every user email to be matched. No data moves until the schema is confirmed ready.
Export and deduplicate Odoo data
We export all Odoo records in the dependency order required by Twenty's relation model: Companies first (res.partner type=company), then People (res.partner type=contact with companyId links resolved), then Opportunities (crm.lead with personId links resolved), then field service orders (fsm.order with customer and worker links resolved), then attachments. During export we run deduplication on res.partner using email as the primary key — duplicate email addresses are surfaced with their Odoo IDs for your team to decide which record to keep before migration commits.
Resolve owners and users by email
Every Odoo user_id and fsm.worker_user_id is matched against Twenty workspace member email addresses. The match produces a cross-reference table (odoo_user_id → twenty_user_id) that drives owner assignment during the write phase. Records with unmatched owners are listed in the audit report with the option to create placeholder Twenty users or assign to a fallback. No record lands in Twenty without a resolved owner unless your team explicitly approves the unassigned record count.
Run test migration with field-level diff
A representative slice of 100–500 records spanning People, Companies, Opportunities, and fsm.order migrates first. We generate a field-level diff comparing the Odoo source values against the Twenty destination values for every mapped field. You review the diff to confirm stage value mapping, owner assignment, companyId linkage, and custom field content. Approval of the test diff is required before the full migration run. Any mapping adjustments are applied before the full run.
Execute full migration with delta pickup and audit log
The full record set migrates against your Twenty workspace using the validated field mappings. A delta-pickup window (typically 24–48 hours) runs in parallel, capturing any Odoo records modified or created during the cutover window so Twenty reflects Odoo's final state at go-live. Every migration operation is logged to an audit table in FlitStack AI's system. If reconciliation reveals a discrepancy (record count mismatch, missing relation), one-click rollback reverts the Twenty workspace to its pre-migration state. Post-migration, we deliver a data integrity report showing record counts, error counts, and owner resolution rates per object.
Platform deep dives
Odoo Field Service
Source
Strengths
Weaknesses
Twenty CRM
Destination
Strengths
Weaknesses
Complexity grading
Standard CRM migration. 1 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 Odoo Field Service and Twenty CRM.
Object compatibility
1 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
Odoo Field Service: Not publicly documented; Odoo documentation notes timeout thresholds for large exports and imports that effectively cap batch size.
Data volume sensitivity
Odoo Field Service doesn't expose a bulk API — REST + parallelization used for high-volume runs.
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 Odoo Field Service to Twenty CRM migration scoping. Not seeing yours? Book a call.
Walk through your Odoo Field Service to Twenty 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 Odoo Field Service
Other ways to arrive at Twenty 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.