CRM migration
Field-level mapping, validation, and rollback between Affinity Fieldreach and Odoo CRM. We move data and schema; workflows are rebuilt natively in Odoo CRM.
Affinity Fieldreach
Source
Odoo CRM
Destination
Compatibility
11 of 12
objects map 1:1 between Affinity Fieldreach and Odoo CRM.
Complexity
BStandard
Timeline
48–72 hours
Overview
Affinity Fieldreach stores relationship data across Persons, Organizations, Deals, and custom fields with a per-user subscription model that becomes expensive as teams grow. Odoo CRM uses crm.lead as a unified model for both raw leads and qualified opportunities, with res.partner serving as the contact and company record simultaneously. We extract Affinity data via their REST API using bearer-token authentication, map Person properties to res.partner fields, Organization records to res.partner companies, and Deals to crm.lead opportunities. Custom fields migrate as Odoo ir.model.fields definitions with type-aware transformations. Affinity automations and workflow rules have no equivalent in Odoo — we export those definitions as JSON for your Odoo developer to rebuild in Odoo's Automations or Server Actions. The migration uses a staged import through Odoo's XML-RPC API with a delta-pickup window capturing any records modified during cutover. Odoo stages translate directly from Affinity deal stages using a value-mapping table, with probability weights re-applied based on Odoo's stage configuration.
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 Affinity Fieldreach 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.
Affinity Fieldreach
Person
Odoo CRM
res.partner
1:1Affinity Persons map directly to Odoo res.partner records. The partner_type field is set to 'contact' for all migrated Persons. Primary email from Affinity populates email on res.partner, and phone populates phone. Affinity Person IDs are stored in a custom source_id field for traceability.
Affinity Fieldreach
Organization
Odoo CRM
res.partner
1:1Affinity Organizations map to res.partner with partner_type set to 'company'. Company names populate the name field. Domain URLs map to website. Additional fields such as industry, employee count, and annual revenue are mapped to their corresponding Odoo partner fields. Parent-child organization hierarchies in Affinity map to parent_id on res.partner, resolved in dependency order during migration.
Affinity Fieldreach
Person-Organization Association
Odoo CRM
res.partner + res.partner.relation
many:1Affinity's N:N Person-to-Organization relationships collapse into Odoo's res.partner model where each Person's primary Organization becomes the commercial_partner_id. Secondary affiliations are preserved as a custom relation table until your team decides on a consolidation rule. The migration includes a detailed report of all secondary links, storing source_affinity_id for each affiliation so you can later merge or tag them in Odoo without re-importing data.
Affinity Fieldreach
Deal
Odoo CRM
crm.lead
1:1Affinity Deals migrate to Odoo crm.lead as opportunities. The deal name maps to name, amount maps to expected_revenue, and close date maps to date_deadline. Owner resolves by email match to Odoo res.users records. Deal stage translates via a value_map to the appropriate crm.stage, and probability weights are re-applied according to Odoo's stage configuration. Custom fields on deals are created in ir.model.fields before the deal batch loads.
Affinity Fieldreach
Deal Stage
Odoo CRM
crm.stage
1:1Affinity deal stages map to Odoo crm.stage records via a value-mapping table. Each Affinity stage name gets a corresponding Odoo stage_id within the target team's stage_ids. Stage sequence order and probability weights are preserved from Affinity's stage configuration. After migration, you can adjust stage names, add new stages, or reassign probability weights directly in Odoo's pipeline view without affecting the underlying data.
Affinity Fieldreach
Activity (Call/Email/Meeting)
Odoo CRM
mail.activity
1:1Affinity activity records (calls, emails, meetings) migrate as Odoo mail.activity entries linked to the corresponding crm.lead or res.partner via res_model and res_id. Activity type, summary, and date are preserved; owner maps by email to res.users. If an activity has an associated note or attachment, those are migrated separately as mail.message or ir.attachment records linked to the same res_model and res_id, ensuring a complete activity history in Odoo.
Affinity Fieldreach
Note
Odoo CRM
mail.message
1:1Affinity notes attached to Persons, Organizations, or Deals become Odoo mail.message records with message_type='comment'. Body content preserves plain text; rich-text notes are converted to HTML for Odoo's message rendering. The note author is resolved by email to a res.partner, and any file attachments are stored as ir.attachment records linked to the same message, keeping the full note context intact.
Affinity Fieldreach
Custom Field (Person)
Odoo CRM
ir.model.fields + res.partner
1:1Affinity custom fields on Persons require Odoo custom field creation via ir.model.fields before data loads. Char fields map directly; selection fields require value_mapping; multi-select fields need dedicated relation tables or serialized storage. We preserve the original Affinity field label as the Odoo field name and generate a unique technical name (e.g., x_affinity_cf_<id>) to avoid conflicts. Field visibility can be restricted to specific user groups if needed.
Affinity Fieldreach
Custom Field (Organization)
Odoo CRM
ir.model.fields + res.partner
1:1Organization custom fields migrate similarly to Person custom fields. Odoo custom fields are created with the same label as the Affinity fields, and a technical name (e.g., x_affinity_org_<id>) is generated to avoid conflicts. Field type determines the transformation — char fields map directly, selection fields use value_mapping, and multi-select fields are stored via dedicated relation tables or serialized fields. Definitions are created in ir.model.fields before the organization batch loads.
Affinity Fieldreach
Custom Field (Deal)
Odoo CRM
ir.model.fields + crm.lead
1:1Deal-level custom fields in Affinity map to custom columns on crm.lead in Odoo. The field type from Affinity (text, number, date, picklist) determines the Odoo field type (char, float, date, selection) and any required value_mapping. Multi-select fields are stored via dedicated many2many tables or serialized JSON in a char field. Custom columns are created in ir.model.fields before the deal batch is imported, and field help text is copied from Affinity.
Affinity Fieldreach
Attachment
Odoo CRM
ir.attachment
1:1Affinity file attachments download from Affinity's storage URLs and re-upload to Odoo via ir.attachment create() calls. The original filename, mimetype, and create date are preserved. Attachments link to res.partner or crm.lead via res_model and res_id. A backup of the original Affinity URL is stored in a custom field for reference, and large files are saved as bytea in PostgreSQL or on the filesystem depending on your Odoo configuration.
Affinity Fieldreach
User/Owner
Odoo CRM
res.users
1:1Affinity owner IDs resolve by email match against Odoo res.users. Unmatched owners are flagged before migration — your Odoo admin either creates the user or assigns records to a fallback owner before the migration commits. For traceability, the original Affinity owner identifier is stored in a custom source_owner_id field on each record. If many owners are missing, a user-provisioning script can be run before the migration to reduce fallback assignments.
| Affinity Fieldreach | Odoo CRM | Compatibility | |
|---|---|---|---|
| Person | res.partner1:1 | Fully supported | |
| Organization | res.partner1:1 | Fully supported | |
| Person-Organization Association | res.partner + res.partner.relationmany:1 | Fully supported | |
| Deal | crm.lead1:1 | Fully supported | |
| Deal Stage | crm.stage1:1 | Fully supported | |
| Activity (Call/Email/Meeting) | mail.activity1:1 | Fully supported | |
| Note | mail.message1:1 | Fully supported | |
| Custom Field (Person) | ir.model.fields + res.partner1:1 | Fully supported | |
| Custom Field (Organization) | ir.model.fields + res.partner1:1 | Fully supported | |
| Custom Field (Deal) | ir.model.fields + crm.lead1:1 | Fully supported | |
| Attachment | ir.attachment1:1 | Fully supported | |
| User/Owner | res.users1: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.
Affinity Fieldreach gotchas
v2 API is not at feature parity with v1
Rate limits constrain bulk export windows
Custom fields silently truncated in third-party integrations
Choice field types are immutable after creation
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
Extract Affinity data via REST API
FlitStack authenticates to Affinity's REST API using bearer-token credentials from your Affinity Settings. We paginate through Persons, Organizations, Deals, Activities, Notes, and custom field definitions in dependency order — custom field schemas load first so downstream record extraction can resolve field IDs to names. API rate limits are managed with a backoff strategy, and any 429 responses trigger automatic retry after the reset window.
Create Odoo custom fields and stage mappings
Before any data loads, FlitStack provisions Odoo custom fields via XML-RPC calls to ir.model.fields for each Affinity custom property. Custom field types are inferred from Affinity's field type metadata (char, selection, multi-select) and mapped to Odoo's field type equivalents. Simultaneously, we create crm.stage records for each Affinity deal stage and build the value_map table linking Affinity stage IDs to Odoo stage_id integers.
Migrate Organizations then Persons then Deals
Odoo's foreign-key model requires Organizations (res.partner with partner_type=company) to load before Persons can link to them. We sequence the migration: Organizations first with parent_id resolution for hierarchy, then Persons with commercial_partner_id set to their primary Organization, then Deals (crm.lead) with partner_id pointing to the Organization and stage_id resolved via the value_map table. Activity records load last, resolving res_model and res_id via the source_affinity_id lookups created during earlier stages.
Run sample migration with field-level diff
A representative slice — typically 100–500 records across Persons, Organizations, Deals, and Activities — migrates first. We generate a field-level diff showing source values from Affinity against the loaded values in Odoo. Your team verifies stage mapping correctness, custom field population, and owner resolution before the full run commits. This sample run also validates API authentication stability and batch-write throughput for your Odoo instance.
Cut over with delta-pickup and audit log
The full migration commits to your production Odoo database. A 24–48 hour delta-pickup window captures any records created or modified in Affinity during the cutover. Every write operation is logged in an audit table including source Affinity ID, destination Odoo record ID, field changed, old value, and new value. One-click rollback reverts all migrated records if reconciliation against the audit log fails. After rollback window closes, the migration is considered complete and your team operates in Odoo.
Platform deep dives
Affinity Fieldreach
Source
Strengths
Weaknesses
Odoo 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 Affinity Fieldreach and Odoo 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
Affinity Fieldreach: Per-minute request limit + per-month account cap + concurrent request limit; exact thresholds vary by plan.
Data volume sensitivity
Affinity Fieldreach 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 Affinity Fieldreach to Odoo CRM migration scoping. Not seeing yours? Book a call.
Walk through your Affinity Fieldreach 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 Affinity Fieldreach
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.