ERP migration
Field-level mapping, validation, and rollback between ERPNext and Odoo ERP. We move data and schema; workflows are rebuilt natively in Odoo ERP.
ERPNext
Source
Odoo ERP
Destination
Compatibility
10 of 11
objects map 1:1 between ERPNext and Odoo ERP.
Complexity
CModerate
Timeline
4-8 weeks
Overview
Moving from ERPNext to Odoo ERP is a schema translation, not a record copy. ERPNext uses a document-based DocType architecture stored in MariaDB where every entity (Customer, Item, Sales Order, Project) is a first-class DocType with a structured schema defined in the UI. Odoo uses a relational model with separate res.partner, product.template, product.product, and stock.quant objects, plus Odoo-specific flags (customer, supplier, seller) on partner records that ERPNext stores as separate DocTypes. We extract ERPNext data via CSV or direct MariaDB query, map each DocType to its Odoo counterpart, and load through Odoo's native import or direct SQL depending on volume and schema complexity. Custom fields stored in ERPNext's Custom Field DocType must be inventoried separately and recreated in Odoo Studio or as XML definitions before data loads begin. Workflows, approval rules, and Frappe server scripts do not migrate; we deliver a written inventory for the customer's Odoo partner to rebuild in Studio or as Python modules.
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 ERPNext object lands in Odoo ERP, including any object-level transformations, lookup resolution, or schema-design dependencies.
Typical mapping — final map is confirmed during the sample migration step.
ERPNext
Customer
Odoo ERP
res.partner (customer flag = True)
1:1ERPNext Customer DocType maps to Odoo res.partner with the customer boolean set to True. We use the customer_name or cust_name field as the partner display name and map customer_name, customer_group, territory, and primary contact details (email, phone, mobile) to their Odoo equivalents. Address records (ERPNext Address DocType) map to res.partner with address_type (invoice, delivery) via the address fields in Odoo's partner model.
ERPNext
Supplier
Odoo ERP
res.partner (supplier flag = True)
1:1ERPNext Supplier DocType maps to Odoo res.partner with the supplier boolean set to True. ERPNext stores supplier-specific fields like default_currency, supplier_type, and country. We map these to Odoo partner fields and populate the seller_ids on the mapped product records after products are loaded so that purchase pricing links correctly. A supplier record that also has customer records in ERPNext creates a single res.partner with both flags set True.
ERPNext
Item
Odoo ERP
product.template + product.product
1:1ERPNext Item maps to Odoo product.template as the definition record with product.product as the variant record (single variant for items without option-based variants). We map item_name to name, item_code to default_code (used as SKU), item_group to product_category, and stock_uom to the Odoo uom_id. Valuation method (FIFO vs Moving Average) maps to Odoo's valuation_type on the product category. Barcodes map to product.barcode on product.product. Item description (HTML) maps to description_sale for the sales description and description_purchase for procurement.
ERPNext
BOM (Bill of Materials)
Odoo ERP
mrp.bom + mrp.routing + mrp.workcenter
1:1ERPNext BOMs with multi-level nesting and operation routing require flattening during extraction and reconstruction in Odoo's MRP module. We export the full BOM tree, resolve ERPNext workstations to Odoo mrp.workcenter records (with capacity, time efficiency, and cost per hour), and build mrp.routing as the operation sequence. The routing is then linked to mrp.bom via the bom_id on each routing operation. If the destination Odoo instance does not include the MRP module, we present three options: install MRP (recommended for manufacturing), flatten to product variants with bill-of-materials as product description text, or maintain BOM detail in a linked product attribute table.
ERPNext
Stock Ledger / Warehouse
Odoo ERP
stock.warehouse + stock.location + stock.quant
1:1ERPNext warehouse structure (including bin-level data via the Bin DocType) maps to Odoo's stock.warehouse and stock.location hierarchy (View, Internal Location, Partner Location, Virtual Location). Open stock ledger entries map to stock.quant with reserved_qty and available_qty resolved per warehouse. We flag whether ERPNext uses perpetual or periodic inventory and configure Odoo's inventory valuation (manual or automated) to match, so that inventory valuation reports are consistent post-migration.
ERPNext
Sales Order
Odoo ERP
sale.order
1:1ERPNext Sales Order with line items, taxes, discounts, and delivery schedules maps to Odoo sale.order and sale.order.line. We extract the full order header (customer reference, currency, payment terms) and all child table rows (packed items, product bundle components) as separate relational CSVs so that the parent-child relationship is preserved at import time. Delivery schedule dates map to sale.order.line.commitment_date. Order status (Draft, Submitted, Cancelled, Closed) maps to Odoo state with ERPNext's workflow states reconciled against Odoo's sale order workflow.
ERPNext
Purchase Order
Odoo ERP
purchase.order
1:1ERPNext Purchase Order maps to Odoo purchase.order using the same line-item extraction approach as Sales Order. We map supplier from ERPNext's supplier field to Odoo's partner_id on purchase.order, line items to purchase.order.line with product, quantity, and price resolved against the product and seller records loaded earlier. Taxes, discounts, and delivery dates transfer similarly. Received and billed quantities in ERPNext map to Odoo's qty_received and invoice_lines for accurate order-to-invoice tracking.
ERPNext
Sales Invoice / Payment Entry
Odoo ERP
account.move + account.payment
1:1ERPNext Sales Invoice maps to Odoo account.move (type = out_invoice or out_refund). ERPNext v14+ decouples payments into a separate Payment Entry DocType linked via the Payment Ledger, meaning an invoice with full payment still shows as open unless we query the Payment Ledger. We run the payment resolution query during extraction, set the Odoo account.move payment_state to matched when full settlement is confirmed, and create account.payment records for partial or full payments. Purchase invoices follow the same pattern with in_invoice and in_refund types. Chart of accounts mapping is validated against the customer's Odoo chart of accounts template before any invoice loads.
ERPNext
Project / Task
Odoo ERP
project.project + project.task
1:1ERPNext Project DocType with nested Tasks, assignees, time logs, and milestone dates maps to Odoo project.project and project.task. ERPNext task hierarchy (parent_task field) maps to Odoo's parent_id on task. Time logs map to account.analytic.line linked to the project if Odoo Accounting is active. ERPNext project_type (External vs Internal) maps to Odoo's privacy_visibility. Task status and ERPNext's workflow states map to Odoo's stage_id on task.
ERPNext
Employee + Attendance + Leave
Odoo ERP
hr.employee + hr.attendance + hr.leave
1:1ERPNext Employee master data (department, designation, date of joining, salary structure) plus attendance and leave records are stored across multiple DocTypes. We consolidate employee profile fields into hr.employee, attendance records into hr.attendance (check_in and check_out per day), and leave applications into hr.leave. ERPNext salary structure assignments map to hr.contract records in Odoo HR if the payroll module is active. If the destination Odoo instance does not include HR Payroll, we preserve salary structure assignments as custom fields on hr.employee for reference.
ERPNext
Custom Fields (Custom Field DocType)
Odoo ERP
Custom Fields (ir.model.fields)
lossyERPNext custom fields stored in the Custom Field DocType (which references parent DocType, defines fieldtype, options, and mandatory flags) must be inventoried separately and recreated in Odoo before data import. We export the full custom field registry during discovery and create Odoo custom fields via Studio (for simpler fieldtypes) or via XML data file for complex fieldtypes, validation rules, and conditional mandatory settings. Data cannot import into non-existent custom fields, so custom field creation must complete before the main data load phase.
| ERPNext | Odoo ERP | Compatibility | |
|---|---|---|---|
| Customer | res.partner (customer flag = True)1:1 | Fully supported | |
| Supplier | res.partner (supplier flag = True)1:1 | Fully supported | |
| Item | product.template + product.product1:1 | Fully supported | |
| BOM (Bill of Materials) | mrp.bom + mrp.routing + mrp.workcenter1:1 | Fully supported | |
| Stock Ledger / Warehouse | stock.warehouse + stock.location + stock.quant1:1 | Fully supported | |
| Sales Order | sale.order1:1 | Fully supported | |
| Purchase Order | purchase.order1:1 | Fully supported | |
| Sales Invoice / Payment Entry | account.move + account.payment1:1 | Fully supported | |
| Project / Task | project.project + project.task1:1 | Fully supported | |
| Employee + Attendance + Leave | hr.employee + hr.attendance + hr.leave1:1 | Fully supported | |
| Custom Fields (Custom Field DocType) | Custom Fields (ir.model.fields)lossy | Mapping required |
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.
ERPNext gotchas
CSV import does not detect or prevent duplicate records
Custom server scripts break silently on version upgrades
BOM routing and workstation data requires manual reconstruction
Payment ledger entries in v14+ are decoupled from invoices
Frappe rate limiting is configurable per-site and undocumented
Odoo ERP gotchas
No rollback for CSV imports
External ID conflicts on re-import
Many2many field encoding in CSV imports
Large export timeouts require batching
Version schema drift between Odoo releases
Pair-specific challenges
Migration approach
Discovery and DocType inventory
We audit the source ERPNext instance across DocTypes in active use, ERPNext version (v13, v14, or v15, since v14 introduced the Payment Ledger split), custom field registry (queried from the Custom Field DocType, not from CSV), active custom server scripts and Frappe Apps, BOM count and routing complexity, open invoice count and payment state, warehouse structure, and project/task hierarchy depth. We also identify any Frappe Apps with third-party DocTypes that cannot migrate portably. The discovery output is a written migration scope with a DocType-to-Odoo-object mapping table and a BOM routing recommendation.
Odoo module selection and schema design
We design the destination Odoo module configuration based on the DocType inventory. We map each ERPNext DocType to its Odoo equivalent, decide which Odoo modules to install (CRM, Sales, Purchase, Inventory, Manufacturing, Project, HR), configure the chart of accounts (Odoo provides country-specific templates; we map ERPNext account codes against the selected template), and create the custom field registry in Odoo Studio or XML. For BOM routing, we present the customer with a structured choice: install Odoo MRP and map full routing, or flatten to simple product BoM without routing. Schema design is validated in a staging Odoo database before production.
Staging migration and reconciliation
We run a full migration into a staging Odoo database using production-like data volume. The customer's operations lead reviews record counts, spot-checks 25-50 records against the ERPNext source (partner details, invoice amounts and payment states, BOM component lists, project task counts), and validates that the custom field values populated correctly. BOM routing reconstruction is validated by generating an Odoo manufacturing order from a sample migrated BoM and confirming the operation sequence matches the ERPNext original. Any mapping corrections are documented and applied to the production migration script before cutover.
Custom field recreation in Odoo
Before any data loads begin, we create the full ERPNext custom field registry in the production Odoo instance. Simple fields (Data, Float, Int, Check, Select, Long Text) are created in Odoo Studio. Complex fields with validation rules, conditional display logic, or non-standard fieldtypes are defined as XML data files and loaded via the Odoo module system. This step must complete before data loads because ERPNext custom fields contain business-critical data that cannot be omitted without corrupting reporting.
Production migration in dependency order
We run production migration in this sequence: chart of accounts (if migrating opening balances), then res.partner (customers and suppliers with deduplication applied), then product.template and product.product, then mrp.workcenter and mrp.bom with routing operations, then stock.quant with warehouse and location hierarchy, then sale.order and purchase.order with line items and child rows, then account.move with payment reconciliation (v14+ Payment Ledger query applied), then project.project and project.task with time logs, then hr.employee with attendance and leave, then attachments as binary fields on their parent records. Each phase emits a row-count reconciliation report. We use Odoo's native CSV import for structured data and direct SQL for large volumes or complex relations that exceed CSV capacity.
Cutover, validation, and rebuild handoff
We freeze ERPNext writes during cutover, run a final delta migration of any records modified during the migration window, then set Odoo as the system of record. We deliver a written inventory of all ERPNext workflows, approval rules, and custom server scripts with Odoo Studio rebuild instructions and a note that Studio can replace most custom field and form logic without code. We do not rebuild ERPNext workflows as Odoo Automations or server actions within migration scope; that work is a separate engagement or handled by the customer's Odoo partner. We provide a one-week hypercare window for reconciliation issues raised by the business team.
Platform deep dives
ERPNext
Source
Strengths
Weaknesses
Odoo ERP
Destination
Strengths
Weaknesses
Complexity grading
Moderate ERP migration. 1 of 8 objects need a mapping; the rest are 1:1.
Overall complexity
Moderate migration
Derived from compatibility, mapping clarity, API constraints, and data volume across ERPNext and Odoo ERP.
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
ERPNext: Configurable per-site; default limits are not publicly documented and are set in site_config.json by the hosting provider. We probe the rate limit headers on discovery and throttle accordingly..
Data volume sensitivity
ERPNext 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 ERPNext to Odoo ERP migration scoping. Not seeing yours? Book a call.
Walk through your ERPNext to Odoo ERP migration with a real engineer — 30 minutes, free, written quote within 24 hours.
Book a free 30 minute consultationAdjacent paths
Other ways to leave ERPNext
Other ways to arrive at Odoo ERP
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.