Requirements gathering on ERP projects gets treated as a business-analyst chore that happens before the interesting work starts. It isn't. It's the phase that determines how many custom modules you end up maintaining for the next six years, and most of the questions that matter are questions only someone who has read the Odoo source would think to ask.
This is the checklist I'd want filled in before I opened an editor. It is deliberately not a list of departments to interview.
1. Map the client's nouns to models before anything else
Every business has five or six words that appear in every sentence they say. "Job." "Load." "Batch." "Run." "Consignment." Write those down on day one and put an Odoo model next to each.
There are three outcomes, and you need to know which one you're in before anyone estimates:
| Outcome | What it looks like | Implementation | Realistic cost |
|---|---|---|---|
| Maps cleanly | Their "consignment" is a stock.picking with a different label on it |
Configuration and terminology only | Hours |
| Maps with extra fields | Their "job" is a project.task plus four fields and an extra state |
_inherit plus a view extension |
An afternoon to a few days |
| Doesn't map | Their "run" is a scheduling entity with its own lifecycle, approvals and reporting | New model, views, security rules, reports | Scope it as its own work package |
The failure mode is silent: a business analyst hears "job", nods, and writes "the system will track jobs." Six weeks later someone discovers that a job spans three sales orders, two warehouses, and can be reopened after invoicing. Ask what the noun is, structurally, and ask what it can be linked to. Cardinality is a requirement, not an implementation detail.
2. Get the numbers, not the adjectives
"High volume" means nothing. Ask for counts, because Odoo's defaults hold up beautifully at one scale and stop being pleasant at another. Each of these numbers changes a decision you cannot cheaply reverse later:
| Ask for | What it decides |
|---|---|
| Orders per day, lines per order | Whether a stock list view is a workable UI or the picking team needs a purpose-built screen |
| Deliveries per day, invoices per month | Whether document generation runs inline or has to be batched and queued |
| Active products and partners | Whether a computed field can stay non-stored, or has to be stored and indexed |
| Concurrent users at peak | Worker count, hosting shape, and whether long operations need to move off the request cycle |
| Peak versus average, by month | Everything above, recalculated for the month that actually matters |
A wholesaler doing 40 orders a day for eleven months and 900 a day in December has a December problem, not an average problem. Design for December.
3. Collect every artefact that leaves the building
Not a description of it. The actual file.
Invoices, credit notes, delivery notes, pick lists, pallet labels, customer statements, EDI payloads, remittance advice, the weekly CSV that goes to the 3PL, the order confirmation email. Each one is a QWeb template, a report, or an export routine, and each one has details — a legal footer, a barcode symbology, a column order the customer's system parses positionally — that nobody mentions until UAT.
Ask two follow-ups per artefact: who receives it, and what happens if it's wrong. The second answer tells you whether it needs an approval step.
While you're here, ask about numbering. Do invoice numbers have to continue from the legacy system's sequence? Does the jurisdiction require gapless numbering? ir.sequence handles this easily if you know before go-live and awkwardly if you find out after the first invoice is posted.
4. Nail product identity early, because it's expensive to change
This one question reshapes the whole data model: is "500ml bottle, blue cap" a variant of one product template, or its own product?
Get it wrong and you're not refactoring — you're re-importing, and every historical transaction, report, and price list built on the old structure comes with you. Establish the template/variant split, the attribute list, and whether attributes affect price, cost, barcode, or packaging.
Then units of measure, which quietly break more implementations than variants do. Ask what they buy in, stock in, sell in, and report in, and get the conversion factors in writing. Fixed factors are fine. Variable ones — catch weight, meat and produce, anything sold by nominal case but invoiced by actual kilos — are a genuine design problem and need to be surfaced in week one, not month four.
Finally, traceability: lots, serials, or neither, and whether expiry dates or shelf life drive picking order. That decision propagates into every stock move.
5. Write the access model down as rules, not as job titles
"Sales reps shouldn't see cost prices" is a sentence. ir.rule records and field-level group restrictions are the implementation, and translating between the two surfaces contradictions fast.
Work through it as access rights and record rules: who can read, write, create, and delete each of the ten or so models that matter, and which records within those models. Then check the exceptions — there is always a regional manager who needs cross-territory read access, and there is always someone who has to approve their own requisition when a colleague is on leave.
Ask the multi-company question explicitly and early: is this one legal entity with several branches, or several res.company records with intercompany transactions between them? Those are different projects with different budgets, and clients use the word "company" for both. If it's genuinely multi-company and multi-country, the fiscal localization packages involved need naming now, because they bring their own chart of accounts, tax logic, and statutory reports.
6. Turn each integration into a contract before the sprint
Every external system needs six answers, and "failure behaviour" is the one nobody volunteers. Capture it in something structured you can hand to whoever builds it:
- name: 3PL despatch feed
direction: odoo -> external
trigger: stock.picking state changes to done
transport: SFTP drop, CSV, one file per picking
payload_owner: 3PL integrations team (external)
idempotency: filename includes picking name; re-send overwrites
on_failure:
retry: 3 attempts, 15 min apart
then: flag picking, notify #ops-alerts, do NOT block invoicing
volume: ~300 files/day, peak 900
The on_failure block is the part that gets designed at 2am during go-live if you skip it here. Decide in advance whether a downstream outage should queue, retry, drop, or halt the upstream process — that is a business decision with money attached, not a technical default.
Name the human owner on the other side too, and confirm they have capacity in your window. External integration owners run on their own release calendar, and that mismatch slips more go-live dates than anything in your own backlog.
7. Define done as real transactions, not as a feature list
Acceptance criteria written as "the system shall support batch invoicing" are unfalsifiable. Acceptance criteria written as "Priya processes these twelve real orders from quotation to paid invoice, unaided" are testable, and they surface the exceptions the requirements phase missed.
Pair that with an explicit data migration scope: which historical data actually crosses over, and at what granularity. Opening balances and open documents are usually enough; full transactional history is usually a request nobody has costed. Whatever the answer, plan the import around stable external IDs so the load is re-runnable — you will run it more than once.
8. The question that eliminates the most custom code
Ask, for each process: what do you do today when it goes wrong?
Not the happy path — the happy path is already in Odoo. What happens when the customer changes the order after picking has started, when a delivery is short, when a payment arrives without a reference, when someone posts to the wrong period. Exceptions are where custom development actually lives, and they're the part clients never think to describe because handling them is muscle memory.
You'll also find that a third of the exceptions have a standard Odoo answer the client didn't know existed. That's the discovery work an Odoo consulting partner is really being paid for, and it's worth more than any amount of documentation.
The limitation worth stating
None of this produces complete requirements, and a checklist that claims otherwise is lying to you. Users cannot describe processes they perform automatically, and some requirements only become visible once someone sees a working screen and says "no, not like that."
The opposite failure is worse and more common: a 200-page specification written before anyone has touched Odoo, which faithfully documents the legacy system's workarounds and gets built as custom modules. Some of the most valuable output of a requirements phase is the list of things the client asked for and then agreed not to build. Keep that list. It's the one you'll reread when someone asks in year three why the system works the way it does.
Get a sandbox in front of the client in week two. Half your open questions answer themselves, and Studio is fast enough to prototype a model and a form view in the meeting itself — which is a much better way to find out you've misunderstood the noun.
Author bio:
The team at Master Software Solutions works on ERP consulting and AI engineering, with a focus on Odoo implementations, integrations, and custom module development for manufacturing, distribution, and food and beverage operations. They write about ERP delivery, requirements practice, and process automation.
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.