Skip to Content

Odoo Accounting

The Odoo Chart of Accounts: Structure, Codes and Multi-Company

The chart of accounts is the one part of Odoo Accounting that is genuinely hard to change after go-live, because every posted journal item points at an account and posted entries do not move. It is worth understanding the model before you build the list.

Written by Hassam SaleemCA Affiliate (ICAP), Odoo Accounting Lead

Part of our guide to Odoo Accounting

What an account actually is in Odoo

An account is a record on the account.account model. The fields that decide its behaviour are a

short list, and almost every setup mistake traces back to one of them:

  • account_type is the selection that tells Odoo what kind of account this is. It drives report

placement, whether the balance carries forward into the next year, and how the account is treated

at close. This is the field that matters most and the one people set carelessly.

  • code is the number you see in the interface and on reports.
  • reconcile is a boolean that decides whether journal items on this account can be matched off

against each other. Receivable and payable accounts need it. Most expense accounts do not.

  • internal_group and group_id position the account for grouping and reporting.

The type is not a label. Setting a bank account to the wrong account_type does not produce a

warning, it produces a balance sheet that is quietly wrong in a way nobody notices until year end.

Account codes are company-specific in Odoo 18 and 19

This is the single most surprising thing about the model, and it is easy to trip over in a

multi-company database.

In Odoo 17, the code is a plain stored column on the account:

code = fields.Char(size=64, required=True, index=True)

One account, one code, everywhere.

In Odoo 18 and Odoo 19, that changed. code became a computed field backed by a

company-dependent store:

code = fields.Char(string="Code", size=64, compute='_compute_code',
                   search='_search_code', inverse='_inverse_code')
code_store = fields.Char(company_dependent=True)
placeholder_code = fields.Char(compute='_compute_placeholder_code')

The consequence is that a single account record can carry a different code in each company.

The model also gained code_mapping_ids and a company_ids many2many, which is the mechanism that

makes a shared account list workable across companies with different national numbering schemes.

Two things follow from this that catch people out:

1. Reading code gives you the code for the company in the current context. If you query over

RPC or in a scheduled action without setting the company deliberately, you get whichever company

the environment happened to be in.

2. An import that sets code sets it for one company. If you expected it to apply to the whole

group, it will not, and the other companies will show the placeholder instead.

If you are on 17 and planning an upgrade, this is a real behavioural change rather than a cosmetic

one, and it is worth testing against your own multi-company setup rather than assuming.

Deprecated became active in Odoo 19

A smaller change, same category of surprise.

Odoo 17 and 18 both declare a deprecated boolean on account.account. Setting it keeps the

account visible for history but blocks it from new entries.

Odoo 19 removes that field. account.account instead carries a standard active boolean, so

retiring an account is ordinary archiving.

The user-facing outcome is nearly identical. What breaks is anything that wrote the old field: an

import template, a data file, a server action or an integration that sets deprecated has nothing

to set on 19.

Structure the chart before you build it

The mechanical work of creating accounts is trivial. The decisions are not:

  • Start from the localisation, do not hand-build. Odoo ships localisation packages that install

a compliant chart for your country. Starting from that and adjusting is faster and safer than

building from a spreadsheet, and it wires up the tax structure at the same time.

  • Decide the depth of your analytic reporting separately. A common and expensive mistake is

encoding department, project or cost centre into the account code, which multiplies the chart and

freezes the structure. Odoo has a dedicated mechanism for that dimension. Use it instead.

  • Keep reconcile honest. Turn it on for accounts you actually match, not as a default.

Reconciliation on an account that never needs it just adds noise to the reconciliation views.

  • Agree the numbering with whoever files your accounts. They will have to work with it long

after the implementation is finished.

Where this connects

The chart of accounts is the foundation the rest of the accounting configuration sits on. Fiscal

positions remap the taxes and accounts that transactions land in, and analytic accounting adds the

reporting dimension that does not belong in the account code. Both assume the chart underneath them

is stable.

FAQ

Questions, answered.

Can I change the Odoo chart of accounts after go-live?

You can always rename an account or add new ones. What you cannot casually do is restructure the chart once entries are posted, because every journal item carries a reference to its account and posted entries cannot be re-pointed without an accounting correction.

  • Renaming an account: safe at any time
  • Adding accounts: safe at any time
  • Changing an account's type: possible, but it changes how the account behaves in reports and in reconciliation
  • Deleting an account with postings: blocked

Expert tip. Decide the structure once, with your accountant, before the first invoice is posted. The cost of getting this wrong is not a configuration change, it is a re-posting exercise.

What is the difference between archiving and deprecating an account?

It depends on your version, and this changed.

  • Odoo 17 and 18 put a deprecated boolean on the account. A deprecated account stays in the list but can no longer be selected on new entries.
  • Odoo 19 removed that field and gave account.account a standard active flag instead, so you archive an account the same way you archive any other record.

The practical effect is the same: stop new postings without destroying history. The field name and the interface control differ, which matters if you have scripts or imports that set it.

Why does the same account show a different code in another company?

Because in Odoo 18 and 19 the account code is company-specific by design. The stored value lives in a company-dependent field, so one account.account record can legitimately present a different code to each company that uses it.

This is the intended behaviour for groups that share an account list but follow different national numbering. If you did not expect it, the giveaway is that the code changes when you switch company while the account name does not.

Does Odoo Community include the full chart of accounts?

Community includes Invoicing, which gives you a chart of accounts, customer invoices, vendor bills and basic payments. The full Accounting app, with bank synchronisation, asset management, deferred revenue and the statutory accounting reports, is Enterprise.

So the chart of accounts itself is not the dividing line. What you can do with it afterwards is.

Keep reading

More on Odoo Accounting.

The full guide, plus the other articles in this cluster.

With CODEerts

Want a hand with this?

We are certified Odoo partners and we do this work for a living.

See how we can helpBook a call