CRM migration
Field-level mapping, validation, and rollback between Handyman and Odoo CRM. We move data and schema; workflows are rebuilt natively in Odoo CRM.
Handyman
Source
Odoo CRM
Destination
Compatibility
11 of 12
objects map 1:1 between Handyman and Odoo CRM.
Complexity
BStandard
Timeline
48–72 hours
Overview
Handyman and Odoo CRM take fundamentally different approaches to customer and job data. Handyman typically stores customer records alongside job definitions in a flat or lightly-relational structure optimized for dispatch and field crews. Odoo CRM separates contacts and companies into res.partner, routes leads and opportunities through crm.lead with stage-based pipelines, and links jobs to Odoo Project or Sale Subscription modules depending on configuration. The migration therefore requires translating Handyman's customer-plus-job records into Odoo's partner-lead-opportunity graph, splitting job histories into Odoo activities and notes, and mapping any service-line custom fields to Odoo custom fields on crm.lead or res.partner. FlitStack AI sequences the migration so partner records load before opportunities, preserving the foreign-key relationships that Odoo's XML-RPC API enforces. We surface Handyman custom properties as Odoo x_studio or x_* custom fields, apply value-mapping for status fields, and flag any Handyman automation rules that must be rebuilt as Odoo server actions or studio workflows post-migration.
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 Handyman 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.
Handyman
Customer
Odoo CRM
res.partner
1:1Handyman customer records map to Odoo res.partner. The partner is created with type 'contact' for individuals and type 'company' for business accounts, matching Odoo's address-book model. Parent-company relationships in Handyman translate to Odoo partner hierarchies via parent_id on res.partner, and any Handyman customer subgroups become Partner.child_ids in Odoo to preserve organizational groupings.
Handyman
Customer (with invoicing history)
Odoo CRM
res.partner + account.move
many:1Handyman customers with paid invoices require both a res.partner record and corresponding account.move records in Odoo. We create the partner first, then link each invoice to it via partner_id on account.move. Invoice line items map to account.move.line with proper account_id selection based on Handyman's service category.
Handyman
Job / Work Order
Odoo CRM
crm.lead (Opportunity)
1:1Handyman job records map to Odoo crm.lead in opportunity mode. The job name becomes crm.lead.name, job status maps to crm.lead.stage_id (Odoo pipeline stage), and the estimated or actual revenue maps to crm.lead.planned_revenue. We preserve the original job number as x_handyman_job_ref for traceability.
Handyman
Job Assignment / Dispatch
Odoo CRM
mail.activity + res.users
1:1Handyman job-to-technician assignments transform into Odoo mail.activity records attached to the corresponding crm.lead, with activity type set to 'Assignment', deadline aligned to the job scheduled date, and user_id pointing to the resolved Odoo res.users record. Email-matching resolves Handyman technician IDs to Odoo user accounts, ensuring every job assignment traces to a valid Odoo user and appears in their activity dashboard.
Handyman
Job Notes / Service Log
Odoo CRM
mail.message (chatter)
1:1Handyman job notes and service-log entries migrate as mail.message records on the corresponding crm.lead in Odoo. Each message preserves the original timestamp, author (mapped by email), and body text. Odoo's chatter interface surfaces these as a chronological service history on each opportunity.
Handyman
Contact / Site Address
Odoo CRM
res.partner (address)
1:1Handyman contact records with site addresses map to res.partner with street, city, state, zip, and country fields populated. When Handyman stores both a billing and service address, we create two res.partner records linked via type 'invoice' and 'other' on the same parent company partner.
Handyman
Custom Property (Job)
Odoo CRM
x_* custom field on crm.lead
1:1Handyman custom properties attached to job records require pre-created Odoo custom fields before migration. We inspect all Handyman custom property names and types, create matching x_* fields on crm.lead via Odoo's Settings > Technical > Models UI or XML-RPC write, then populate them during the data load. Selection-type Handyman properties become Odoo selection fields with value_mapping.
Handyman
Custom Property (Customer)
Odoo CRM
x_* custom field on res.partner
1:1Handyman custom properties on customer records migrate to Odoo res.partner custom fields using the same pre-creation workflow as job custom properties. Fields are created on res.partner model, typed as char, integer, float, date, or selection matching Handyman's data type for each property.
Handyman
Quote / Estimate
Odoo CRM
sale.order
1:1Handyman quotes or estimates map to Odoo sale.order in state 'draft'. Order lines are created from Handyman line items with product_id linked to the matching Odoo product.product or created as a product.template with type 'service'. The sale.order is linked to the corresponding crm.lead via opp_id if the quote originated from a lead.
Handyman
Invoice
Odoo CRM
account.move
1:1Handyman invoices map to Odoo account.move with type 'out_invoice'. Partner_id references the corresponding res.partner. Invoice lines populate account.move.line with account_id resolved from Handyman's service category mapping. State is set to 'posted' for paid invoices, 'draft' for open ones. Payment records map to account.payment linked via payment_reference.
Handyman
User / Technician
Odoo CRM
res.users
1:1Handyman technician and user records resolve to Odoo res.users by email matching. If an exact email match exists in Odoo, we link the Handyman record to that user. For unmatched technicians, we flag them for pre-provisioning before migration or assign their records to a fallback Odoo user to prevent orphaning job assignments.
Handyman
Attachment / Photo
Odoo CRM
ir.attachment
1:1Handyman job photos and attachments re-upload to Odoo as ir.attachment records linked to the target crm.lead via res_model='crm.lead' and res_id=<lead_id>. File binary content is stored in Odoo's filestore path. Size limits per Odoo configuration apply; we chunk large batches to avoid timeouts during the import run.
| Handyman | Odoo CRM | Compatibility | |
|---|---|---|---|
| Customer | res.partner1:1 | Fully supported | |
| Customer (with invoicing history) | res.partner + account.movemany:1 | Fully supported | |
| Job / Work Order | crm.lead (Opportunity)1:1 | Fully supported | |
| Job Assignment / Dispatch | mail.activity + res.users1:1 | Fully supported | |
| Job Notes / Service Log | mail.message (chatter)1:1 | Fully supported | |
| Contact / Site Address | res.partner (address)1:1 | Fully supported | |
| Custom Property (Job) | x_* custom field on crm.lead1:1 | Fully supported | |
| Custom Property (Customer) | x_* custom field on res.partner1:1 | Fully supported | |
| Quote / Estimate | sale.order1:1 | Fully supported | |
| Invoice | account.move1:1 | Fully supported | |
| User / Technician | res.users1:1 | Fully supported | |
| Attachment / Photo | 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.
Handyman gotchas
Pricing model terminology varies across destinations
Service history chunking for accounts with large job counts
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
Audit Handyman data export and Odoo target schema
FlitStack AI pulls a full export from Handyman via CSV or API (depending on plan tier), inventories all object types (customers, contacts, jobs, invoices, attachments), and catalogs every custom property. We simultaneously inspect the target Odoo instance's res.partner, crm.lead, crm.stage, res.country, res.country.state, and account.chart.template to map available fields and identify missing custom fields that must be pre-created. The audit report lists record counts per object, custom property count, and any Handyman data anomalies (duplicate emails, orphaned records, missing required fields) so your team can clean source data before migration.
Create Odoo custom fields and resolve user mapping
Using the audit output, we create all required x_* custom fields on res.partner and crm.lead in the Odoo instance (developer mode for Community; Studio for Enterprise). We simultaneously run the technician-to-Odoo-user email matching pass and surface any Handyman technicians with no corresponding Odoo res.users record. Your Odoo admin either pre-provisions those users or designates a fallback user before we proceed to data loading.
Load partners, then leads, then invoices in dependency order
Odoo's XML-RPC enforces foreign-key constraints: crm.lead.partner_id requires a valid res.partner ID, and account.move.partner_id does the same. We sequence the migration as Partners → Contacts → Leads (with job data) → Invoices. Partner child contacts load as第二条 res.partner records under their parent company partner. Job notes load as mail.message records on each crm.lead after lead creation completes. This order prevents orphaned records and foreign-key rejection errors that would otherwise roll back individual API calls.
Run sample migration with field-level diff
Before committing the full dataset, FlitStack AI runs a representative sample (typically 200–500 records spanning customers, jobs, and invoices) into the live Odoo instance. We generate a field-level diff comparing the source Handyman values against the destination Odoo fields for every mapped property. You review the diff to confirm stage mapping, user_id resolution, custom field population, and invoice state assignment. Any corrections to value mappings or user resolution are applied before the full run.
Execute full migration with delta-pickup window
The full migration loads all remaining records into Odoo. A delta-pickup window (24–48 hours after the full load timestamp) captures any Handyman records created or modified during the cutover — new jobs, updated statuses, recently sent invoices. FlitStack AI logs every API operation to an audit table including record ID, source object, destination object, field mappings applied, and timestamp. If reconciliation finds missing or mismatched records, one-click rollback reverts the Odoo instance to its pre-migration state so the run can be corrected and re-executed without data corruption.
Platform deep dives
Handyman
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 Handyman 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
Handyman: Not publicly documented.
Data volume sensitivity
Handyman 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 Handyman to Odoo CRM migration scoping. Not seeing yours? Book a call.
Walk through your Handyman 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 Handyman
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.