OpenERP 5 - Creating a chart of accounts - first draft

Following up on our permanent quest to harness the power of OpenERP, this article will consider the specific challenge of building a chart of accounts. One of the most difficult things in OpenERP when customising it for a specific country is defining the chart of accounts. Well, the most difficult part is actually that there is no documentation on how to do this... Although I am no expert in designing chart of accounts, I have spent a considerable amount of time trying to figure out  the structure of the modules, and this is the result of my work, both to avoid me looking into this info again in one year time, and to ease the work of others, trying to provide accurate information all along. The files structure A chart of accounts is a module. Generally speaking, as it is considered part of the "localization" of OpenERP, it will be named something like "l10n_chart_xx" where "xx" is the two-letters code of your country. Let's say I want to implement a chart of accounts for Peru. My module will thus be called "l10n_chart_pe". In order to prepare my module, I will create a local l10n_chart_pe directory, which will contain the files of my module. When completing my module, I'll just zip the whole directory and import it into OpenERP. is a necessary file. However, it doesn't have to contain anything. Generally, in other modules, it will contain the module header with information about the license and who to contact. is also a necessary file. This one, though, needs to be filled. It also needs to contain references to other files used inside the same module. All other files should be referenced in and the files will depend on how far you want to implement your chart of accounts. This is an example of how the file should look like:
{ "name" : "Peru", "version" : "0.9", "author" : "BeezNest Belgium SPRL", "category" : "Localisation/Account Charts", "depends" : ["account","account_report","base_vat","base_iban", "account_chart"], "init_xml" : [], "demo_xml" : [], "update_xml" : ['account_chart.xml'], "installable": True }
The name tag should contain the name of your module. The description tag, although not mandatory, should be used to describe the module in a longer sentence The version tag should contain the version (two digits) which will appear as an extension to the version number of OpenERP this module is installed in. The author tag should contain the name of the individual author(s) or the company that invested time to build this module. The category tag should contain a category representing the type of module this is. In this case, Localisation/Account Charts is the category used for all charts of accounts. The depends tag is very important, and should list the modules necessary to the installation of this module. Generally speaking, you should be good with the proposed list of modules ("account","account_report","base_vat","base_iban", "account_chart"), but you might want to skip base_vat or base_iban if you don't plan on using them. (Definition to be confirmed) The init_xml tag lets you define some data to be added on initialisation of this module's installation. (Definition to be confirmed) The demo_xml tag lets you define a set of demo data to go with your module, that will be installed only if the user checks the "Demo data" box in the Module Installation Scheduler screen. (Definition to be confirmed) The update_xml tag lets you define a set of data that need to be added to your system upon upgrade with the current module. The installable tag (to be set to either True or False without quotes) defines whether this module should let the admins install it or not. Obviously, this will be True in most cases. As you have seen, the update_xml tag contained only one item: the name of an XML file. This file will contain the real data for the account chart, and is the main topic of the following section. account_chart.xml This file will contain the core of the chart of accounts. Although the chart of accounts itself could be split between several files (one for accounts, one for taxes, one for tax codes and possibly many others), we will define them all in one file here: account_chart.xml. We will take care of indicating a clear comment to separate them. Here is what the file should look like, entries excepted.
<?xml version="1.0" encoding="utf-8"?> <openerp> <data noupdate="True"> </data> </openerp>
Now, inside the <data> tag, we will put a considerable amount of "record" tags. The first series will be for the types of accounts, the secont for the accounts themselves, the third will contain the tax codes, the next one will contain the taxes themselves, and the final section will contain the definition of a template to use inside OpenERP to define other accounts. Each of the following sections is considered to be included inside this <data> tag. The sections follow one another without any kind of specific splitting other than an XML comment First section: types of accounts
<!-- Account types (account.account.type), based on UK minimal --> <record model="account.account.type" id="account_type_receivable" > <field name="name">Recevible</field> <field name="code">receivable</field> <field name="close_method">unreconciled</field> </record> <record model="account.account.type" id="account_type_payable" > <field name="name">Pagable</field> <field name="code">payable</field> <field name="close_method">unreconciled</field> </record> <record model="account.account.type" id="account_type_view"> <field name="name">Vista</field> <field name="code">view</field> <field name="close_method">none</field> </record> <record model="account.account.type" id="account_type_income" > <field name="name">Ingreso</field> <field name="code">income</field> <field name="close_method">none</field> </record> <record model="account.account.type" id="account_type_expense"> <field name="name">Gastos</field> <field name="code">expense</field> <field name="close_method">none</field> </record> <record model="account.account.type" id="account_type_tax"> <field name="name">Impuestos</field> <field name="code">tax</field> <field name="close_method">unreconciled</field> </record> <record model="account.account.type" id="account_type_cash"> <field name="name">Sencillo</field> <field name="code">cash</field> <field name="close_method">balance</field> </record> <record model="account.account.type" id="account_type_asset"> <field name="name">Activo</field> <field name="code">asset</field> <field name="close_method">balance</field> </record> <record model="account.account.type" id="account_type_equity"> <field name="name">Capital</field> <field name="code">equity</field> <field name="close_method">balance</field> </record> <record model="account.account.type" id="account_type_other"> <field name="name">Others</field> <field name="code">other</field> <field name="close_method">none</field> </record>
What do we find here? First, we have an XML comment explaining what the next section is. Comments are made using "<!--" and "-->". Next, we have the first <record> tag, which has a model and a id attribute. Both these attributes are mandatory. Model defines the object model that this record is going to use, and id serves as a unique ID that will be referenced later on by other records in this file. Inside this <record> tag, we find several <field> tags. These tags define additional properties for the record. The name tag defines the name to be shown to the user inside the OpenERP interface. The code tag is a unique code that could be used as a reference in other records. The close_method tag can be a choice of none, unreconciled, balance. These values will define how this account type will be "closed" at the end of the fiscal year. This requires accounting notions to be set adequately. The example above doesn't apply these settings correctly. Second section: the accounts
<record id="chart0" model="account.account.template"> <field name="name">Plan de cuentas</field> <field name="code">0</field> <field name="type">view</field> <field name="user_type" ref="account_type_view"/> </record> <record id="chart1" model="account.account.template"> <field name="code">1</field> <field name="reconcile" eval="False"/> <field name="parent_id" ref="chart0"/> <field name="type">view</field> <field name="user_type" ref="account_type_view"/> <field name="name">ACTIVO CORRIENTE</field> </record> ... <record id="chart10" model="account.account.template"> <field name="code">10</field> <field name="reconcile" eval="False"/> <field name="parent_id" ref="chart1"/> <field name="type">view</field> <field name="user_type" ref="account_type_view"/> <field name="name">CAJA Y BANCO</field> </record> <record id="chart12" model="account.account.template"> <field name="code">12</field> <field name="reconcile" eval="False"/> <field name="parent_id" ref="chart1"/> <field name="type">view</field> <field name="user_type" ref="account_type_view"/> <field name="name">CLIENTES</field> </record> ... <record id="chart121" model="account.account.template"> <field name="code">121</field> <field name="reconcile" eval="False"/> <field name="parent_id" ref="chart12"/> <field name="type">other</field><field name="user_type" ref="account_type_other"/> <field name="name">Facturas por cobrar</field> </record>
As you might have seen in this example, there is a certain structure defined. We will try to analyse it in this section. As for the account types, we have a <record> tag with a model of account.account and a unique ID that will later be used as a reference. This <record> tag contains several <field> tags that generally contain a name (that identifies the element) and a ref or eval attribute (that gives the value of the element). The name tag defines the name that will appear to the user using the chart of accounts. The code tag is an idnetifier that will appear to the user as well. The type tag gives the type of the account. For container accounts, this should be set to view. For other accounts, we have used other in this example, but they could be defined as any of the type codes defined in the first section. The user_type gives another type of reference to the account type. It should match the record's id attribute as defined in the type itself, in the same type as the one defined for the type element. (Definition to be confirmed) The reconcile element defines how this account should be reconciled at the end of the financial year. The parent_id element defines, in case of a child account (depending on another parent account), the id of the <record> tag that matches the parent. Third section: the tax codes Taxes combine VAT (or any variation like IVA, IGV, IVG, TVA, BTW, etc) and any other type of taxes. Defining tax codes is like defining tax types. You have to do it before you define actual taxes.
<!-- tax codes --> <record model="" id="vat_code_balance_net"> <field name="name">Tax balance to pay</field> <field name="parent_id" eval="False"/> </record> <record model="" id="vat_code_due_tva"> <field name="name">Tax Due (Tax to pay)</field> <field name="parent_id" ref="vat_code_balance_net"/> </record> <record model="" id="vat_code_payable"> <field name="name">Tax payable</field> <field name="parent_id" ref="vat_code_balance_net"/> </record> <record model="" id="vat_code_base_net"> <field name="name">Tax bases</field> </record> <record model="" id="vat_code_base_due"> <field name="name">Base of taxed sales</field> <field name="parent_id" ref="vat_code_base_net"/> </record> <record model="" id="vat_code_receivable_net"> <field name="name">Base of taxed purchases</field> <field name="parent_id" ref="vat_code_base_net"/> </record>
As you can see, this section is quite simple. There should be the same kind of tax code for pretty much any country with a VAT system (or similar). Although not mandatory, you can define a parent_id of False for the root element of the tax codes. Fourth section: the template Although the template deal is something you can use in the Financial Management menu of OpenERP, it is still a mistery to me. However, the following bit of code seems to do the trick:
<!-- template definition --> <record id="l10npe_chart_template" model="account.chart.template"> <field name="name">Peruvian PCNorm</field> <field name="account_root_id" ref="chart0"/> <field name="tax_code_root_id" ref="vat_code_balance_net"/> <field name="bank_account_view_id" ref="chart104"/> <field name="property_account_receivable" ref="chart121"/> <field name="property_account_payable" ref="chart421"/> <field name="property_account_expense_categ" ref="chart601"/> <field name="property_account_income_categ" ref="chart701"/> </record>
Where account_root_id references the root record of the chart of accounts, tax_code_root_id defines the root record of the tax code elements, bank_account_view_id references the account that deals with bank accounts (in this case, 104), property_account_receivable references the account that is linked to customer invoices to be paid, property_account_payable references the account that is linked to suppliers invoices to be paid, property_account_expense_categ references the merchandises ordering account, and finally property_account_income_categ references the merchandises sales. Fifth section: the taxes
<!-- tax codes --> <record id="tax1" model=""> <field name="chart_template_id" ref="l10npe_chart_template"/> <field name="name">Impuesto General a las Ventas</field> <field name="amount" eval="0.170000"/> <field name="type">percent</field> <field name="account_collected_id" ref="chart4011"/> <field name="account_paid_id" ref="chart4011"/> <field name="base_code_id" ref="vat_code_base_due"/> <field name="tax_code_id" ref="vat_code_due_tva"/> <field name="ref_base_code_id" ref="vat_code_receivable_net"/> <field name="ref_tax_code_id" ref="vat_code_payable"/> </record> <record id="tax2" model=""> <field name="chart_template_id" ref="l10npe_chart_template"/> <field name="name">Impuesto a la Renta 6%</field> <field name="amount" eval="0.060000"/> <field name="type">percent</field> <field name="account_collected_id" ref="chart4017"/> <field name="account_paid_id" ref="chart4017"/> <!-- impuesto a la renta - chart88 ? --> </record> ...
The complexity is a bit more impressive here... Every tax record has a model (as usual), a name, an amount (which defines the amount of the tax in combination with the type tag), a type (which defines the type of amount implied by the tax), an account_collected_id (which references an account from the chart of accounts which this tax is collected from), an account_paid_id (which references an account from the chart of account which this tax is paid to). Additionnally, and only for some of the accounts (and this is still a black spot of information for me), you can define a combination of base_code_id, tax_code_id, ref_base_code_id and ref_tax_code_id, which all reference a tax type as defined in the previous section. Conclusion Using these sections and this summary explanation, and comparing them with the current charts of accounts, you should be able to build something that works for your own chart of accounts... There are numerous additional options to define extensions to this chart of accounts, but it is difficult to find any meaningful documentation around the OpenERP website, so if you find some, don't hesitate t leave a comment.


Thanks for good article it helped me a lot. Creating chart for me still black hole. I don't know when to use reconcile and what type of close_method I must use.

My loaded data are in account.account.template, but not in account.account, I don't know why? Thanks for reply.

Nice article.

You need not write xml. You can write csvs too.
Its more readable and easier to mofiy,

An example would be l10n_chart_uk_netinsight in trunk-extra-addons

In reply to by YW


Great info! Thanks.

Hello, i need to include an xml with the consolidated childrens, how can i do that


The 'ref_tax_code_id' and 'ref_base_code_id" are used when refunding, and should thus never(?) be the same as "tax_code_id".

I need to begin working on localization for UAE where there exists no tax . So what would be my option?

In reply to by YW


Hi v2nath,

Sorry you would have to ask that on the OpenERP forum. We are not contributing to OpenERP at this time and the versions have changed considerably since this post. Best of luck!