Leaving NetSuite is rarely a technology decision. It usually starts with a renewal quote that has drifted a long way from what the business actually uses, a per-user model that punishes you for giving warehouse staff read access, and modules bought in a growth year that nobody has opened since. Odoo is the common destination, and the functional fit is normally settled in a few workshops. The project then stalls on one question: how do we get years of data out without breaking the audit trail or misstating the opening balance sheet?
That question is expensive because the hard half of the work sits on the NetSuite side. A saved search export gives you the transaction line but not the inventory detail subrecord. A flat CSV loses the internal IDs that hold the relationships together, so customers, items and open transactions arrive in Odoo as three unrelated piles. Governance limits kill a naive script halfway through a large extract. Amounts exist in both the transaction currency and the base currency of the subsidiary, and choosing the wrong one silently misstates the opening trial balance. Consultancies price that risk, which is why a mid-market move is quoted in tens of thousands before anyone has looked at your data.
This toolkit is the repeatable part of that work, built for your NetSuite account and your target Odoo database.
What ECOSIRE builds
1. The extraction layer, inside NetSuite
We build SuiteScript 2.1 extract jobs that run inside your own account. High-volume tabular pulls use SuiteQL through the SuiteTalk REST query service; record-level pulls that need subrecords — inventory detail, address subrecords, transaction lines with their custom segments — run as Map/Reduce scripts that checkpoint and yield, so a million-row extract finishes instead of dying at a governance limit. Scope is defined by saved searches you can open and read, so you can see exactly which records are in each batch before anything moves.
Every extracted row carries its NetSuite internal ID. That ID becomes the external identifier on the Odoo side, which is what makes the whole process re-runnable: a second pass updates the record it created the first time instead of duplicating it. RESTlet endpoints allow controlled re-pulls of a single object or a date-bounded delta during cutover.
Record coverage typically includes subsidiaries, currencies and exchange rates, accounting periods, the chart of accounts, customers, vendors, contacts and their addresses, items across inventory, non-inventory, service, kit/package, assembly and matrix types, units of measure, price levels, tax codes and tax groups, open sales orders and purchase orders, open invoices, credit memos, vendor bills and vendor credits, inventory on hand by location and bin including lot and serial numbers, item costing, journal entries, and GL balances by period. Custom records, custom fields and custom segments are extracted alongside the standard ones.
2. The mapping layer
Extraction is mechanical; mapping is where migrations succeed or fail, so it is an explicit, signed-off artefact rather than a set of assumptions buried in a script. You receive a mapping workbook covering NetSuite account to Odoo account, subsidiary to Odoo company, location to Odoo warehouse and stock location, item type to Odoo product type and tracking policy, unit of measure, tax code to Odoo tax, payment terms, and custom segment to analytic account or analytic distribution.
The loaders fail loudly on anything unmapped. A value that has no target does not get a best guess and it does not get silently dropped — it lands on an exception report with the record that referenced it.
3. The load layer
Loaders write into Odoo through its external API, in dependency order, keyed by external ID so every run is idempotent. Opening balances are posted as an opening journal entry per company and currency into the correct fiscal period. Open receivables and payables are loaded as real open invoices and bills rather than being lumped into a control account, so aging, statements and payment matching work from day one. Inventory arrives with quantity, cost, location and lot or serial detail intact.
History is a decision, not a default. We will present the trade-off plainly during scoping: full transactional history gives you drill-down in Odoo at the cost of load time and database size; summarised monthly journals give you a clean, fast ledger while you retain NetSuite in read-only mode for statutory lookback. Either is supported, and mixed approaches — full detail for two years, summarised before that — are common.
4. Reconciliation and cutover
A migration is only finished when someone can prove it. The toolkit produces reconciliation reports on both sides: trial balance parity by account, period and currency; AR and AP aging parity by partner; inventory quantity and valuation parity by product and location; and record counts per object with an exception list for every row that did not load and why.
Cutover is rehearsed, not attempted. We run at least one full dry run into a scratch Odoo database, hand you the parity reports to review, then run a delta pass over the freeze window so only the records changed since the rehearsal move on cutover night. You get a written go/no-go checklist with the numbers that must match before anyone signs off.
Who this is for
Finance and IT leaders at companies of roughly twenty to two hundred staff who have decided to leave NetSuite and need the extraction half handled by people who know the platform. It also fits Odoo implementation teams who are confident on the Odoo side and want the NetSuite extraction, mapping and reconciliation delivered as a defined workstream instead of a discovery exercise.
How delivery works
This is built to order. There is no downloadable package, because the toolkit is configured against your record set, your chart of accounts and your target Odoo version.
1. Scoping call. We inventory what actually exists: subsidiaries, currencies, transaction volumes by type and year, custom records and segments in use, how much history you must carry, and which Odoo version and hosting you are moving to. 2. Fixed quote and specification. You receive a written scope naming every object in and out, the history strategy, the reconciliation reports, and the cutover plan, at a fixed price with dates. 3. Build. The extraction scripts are developed as an SDF project against your sandbox account; loaders are developed against a scratch Odoo database. 4. Rehearsal in test. A full dry run into a test Odoo database, with parity reports delivered for your finance team to review and challenge. Mapping corrections are expected at this stage and are included. 5. Production cutover. Freeze window, delta extract, load, reconciliation, go/no-go against the agreed numbers. 6. Support window. A defect-fix window after cutover covering anything that does not match the signed specification, plus the source so you can re-run any object yourself.
Typical lead time is one working week from approved quote to first rehearsal, longer where history volume or subsidiary count is unusually high — we will say so in the quote rather than after. We do not decommission your NetSuite account for you; keeping it read-only for statutory history is normally the right call, and that is your decision to make with your auditor.