DEMO DATAS FOR ODOO

Preparation of a test enviroment for Odoo

Benjamin Bachmann

WHY OWN DEMO DATAS?

It often happens that we write an add-on that offers new features, but where standard demo data is not enough; or we want to give predefined settings to the add-on. In the cases mentioned, we have to expand the whole thing with demo data.

Data / demo data is mostly records, which integrate different entries into the database and logically link fields. By creating demo data, you can start a server in which, for example, already predefined users, products or orders are available and you have a live similar environment.

Normal odoo demo data is integrated via the XML files which are listed under __openerp__.py under the key "demo". This data is only imported if the user has clicked on the hook with demo data when creating the database.

The normal XML data is always added to the database during installation. Unless set with the "noupdate" flag (<data noupdate = "1">), the demo data will only be added to the system once during installation, without this tag the data will always be reset to its original value optimal test environment when testing something and modifying entries, where the data is easily restored through an update.

HOW DO I CREATE DEMODAT?

There are several ways to create demo data. On the one hand via XML records, CSV files or Yaml Records. Based on the res_partner model, I will show how to create the demo data for all three possibilities.

EXAMPLE OF A RES PARTNER FOR ODOO

XML FILE

As you can see here, adding this add-on by the data.xml adds a res.partner to the database. The noupdate = "1" flag will only do this once and not every time this add-on is updated. XML files always start with the entry <?Xml version="1.0" encoding="utf-8"?>, Which indicates the Odoo typical encoding of UTF-8. This is followed by the Odoo <openerp> entry, which then contains the data in <data>. Here are the records listed, which we want to add to the database.

The record first mentions the model responsible for the entry in the database. In our example of the res partner, this is the model res.partner. By <record model="res.partner" id = "res_partner_1"> a new entry with the ID res_partner_1 is added to the model.

Then follow the fields, which we want to fill with data. To add a name to the res.partner with the ID res_partner_1, we call the field name with <field name="name">Max Mustermann</field> and add it to Max Mustermann.
True or False is added by <field name="customer" eval="False"/> using eval. References to other fields or entries are added by <field name="company_id" ref="base.main_company"/> by specifying the field as a reference.
With large amounts of data you can reach fast, very long XML files, which is why we now come to the CSV files. In Odoo we can also read directly CSV files. This is especially advantageous for large data sets.

<?xml version="1.0" encoding="utf-8"?>
<openerp>
    <data noupdate="1">
     <record model="res.partner" id="res_partner_1">
     <field name="name">Max Mustermann</field>
     <field name="company_id" ref="base.main_company" />
     <field name="parent_id" ref="base.main_partner" />
     <field name="use_parent_address" eval="True" />
     <field name="type">contact</field>
     <field name="customer" eval="False" />
     <field name="supplier" eval="False" />
     <field name="is_company" eval="False" />
            <field name="agent" eval="False" />
     <field name="zip">12345</field>
     <field name="city">Neustadt</field>
     <field name="street">Musterstrasse 1</field>
     <field name="phone">123456789</field>
     </record>
    </data>
</openerp>

CSV FILE

In the CSV, the first line tells the system in which fields of the model we want to write the information into the database. In the following lines the information will be listed. It is important that in Odoo, the CSV files bear the name of the model in which you want to write the data. In our case this would be res.partner.csv.
CSV files do not have a "noupdate" flag and are overwritten each time during the update. But CSV data also have disadvantages: they do not have the same rights as XML files.
I was not able to create a user via a CSV file. This is also logical, because you can not use the backend (and CSV file), just a new administrator can import and get access to the system.

„id“,“name“,“company_id“,“parent_id","use_parent_address",type","customer","supplier","is_company","agent","zip","city","street","phone",
„res_partner_1","Max Mustermann“,“base.main_company“,"base.main_partner","True","contact","False","False","False","False","12345","Neustadt","Musterstrasse 1","123456789"

YAML FILE

The main advantage of demo data about Yaml is that the data is only volatile data in the database when needed for a test. They are then created for the test and deleted from the database after the test. Of course you can also use them as normal demo files by adding them in the __openerp__.py of the add-on in the section 'data':[].
Yaml Records are ideally combinable with Yaml tests, because in any case you want to test, you can create an entry without further ado. This record can then be changed by a test in one direction and then during the test, reset to the original state and tested in another direction.
For large amounts of records are not Yaml test advantageous because the overview is lost quickly.

-
  !record {model: res.partner, id: res_partner_1}:
  name: Max Mustermann    
    company_id: base.main_company
    parent_id: base.main_partner
    use_parent_address: True
    type: contact
    customer: False
    supplier: False
    is_company: False
    agent: False“
    zip: 12345
    city: Neustadt
    street: Musterstrasse 1
    phone: 123456789

SUMMARY

In XML files you can integrate permissions and functions into a demo file.
CSVs are ideal for large amounts of data because they can easily be created or extracted from the database.
Yaml files are ideal for testing, as this way you can easily create situation and entries in the database for a test.

EXPORT AND TRANSFORM LIVE DATA FROM CSV TO XML

From the Odoo system you can export very well entries from the database into a CSV. As I noted before, there are situations where you have to address certain fields differently or you do not have permissions to create entries in the database.
Here's an example about creating demo data, for automatically creating users in the database, which is only possible via XML.

Odoo CMS - a big picture

SELECTION FOR EXPORT

We select users under the settings. Then we select the users that we want to export and then click on the "More" button to export the users.

Odoo CMS - a big picture

FIELDS SELECTION

Odoo now gives us the opportunity to decide in advance which information we want to export. This is useful, for example, if we know that we do not need specific fields because they are set automatically when you create them.

Odoo CMS - a big picture

EXPORT IN CSV

After selecting the fields, all we have to do is confirm with "Export To File" and Odoo will provide us with a CSV file. The CSV file immediately carries the correct name of the model in which we want to insert the demo data into our new database. This would be important if we want to use the CSV file as a demo file.

CONVERT THE CSV TO AN XML

We could now manually create an XML from the CSV. But with very large data, with hundreds or more entries, this would be very cumbersome and take a long time. I use online tools for such cases, which accelerate the process rapidly. With this converter one writes once the structure of the XML file to be created and afterwards all other records are written in an XML. It is also important to note what kind of field it is - in the following example I have marked the differences in color.

Odoo uses a comma (,) when exporting the CSV, to separate the data, and the data is written to Double Quotes ("), which must be reported to the converter.

CSV to XML Converter

  <record model="res.users" id="##1##">
               <field name="partner_id" ref="##2##"/>
               <field name="login">##3##</field>
               <field name="password">##4##</field>
               <field name="email">##5##</field>
               <field name="lang">##6##</field>
               <field name="tz">##7##</field>
               <field name="action_id" ref="##8##" />
               <field name="company_id" ref="##9##" />
               <field name="company_ids" eval="[(4, ref('##10##'))]" />
   </record>

After the conversion, an XML is output to which you have to add the typical Odoo information. Now you have a demo file, which you can add to the database.

   <?xml version="1.0" encoding="utf-8"?>
<openerp>
    <data noupdate="1">
               <record model="res.users" id="user_1">
                    <field name="partner_id" ref="res_partner_1" />
                    <field name="login">user_1</field>
                    <field name="password">123456</field>
                    <field name="email">user@mail.com</field>
                    <field name="lang">de_DE</field>
                    <field name="tz">Europe/Berlin</field>
                    <field name="action_id" ref="board.open_board_my_dash_action" />
                    <field name="company_id" ref="base.main_company" />
                    <field name="company_ids" eval="[(4, ref('base.main_company'))]" />
                </record>
    </data>
</openerp>

IMPORTING DEMO DATAS

When importing demo data, care must be taken to ensure that entries and fields that you want to write already exist or are created. In our example, we can only create the user if we have previously created the partner. (field name="partner_id" ref="res_partner_1") The user needs a reference to a partner.
In the __openerp__.py then the following order must be followed for demo data, so that dependent entries

Demo datas that should only be installed if demo data is desired.

  'demo': [
            'demo/res.partner.xml',
            'demo/res.users.xml',
    ],

Demo datas, which are always desirable, because they predefine settings for an add-on or create standard users.

    'data': [
            'demo/res.partner.xml',
            'demo/res.users.xml',
    ],

WORKFLOWS

CREATING WORKFOWS AND FURTHER ASSOCIATED RECORDS

In Odoo you can also create more complex records via demo data by creating workflows or using existing ones.
If we have created an order, via a record, with all their connections, we can now tell the system through the workflow that it will be put into another status. As a result, demo data is created as if someone had created a sale order and, as in our example, this already confirmed.

<workflow action="order_confirm" model="sale.order" ref=„demo_addon.sale_order_1“/>

Furthermore, we can extend this by giving the order a relationship with other Odoo modules. The code creates the order in the system as if it is considered paid, and the entire delivery process with invoices, goods receipts and goods issues is put into effect. The advantage is that the user receives demo data that are all connected to each other and how they were created in the live system. This provides a very good test environment because it involves real workflows.

<record id="demo_addon.sale_order_1" model="sale.order">
            <field name="warehouse_id" ref="stock.warehouse0"/>
            <field name="order_policy">prepaid</field>
</record>

Also a useful feature is, if you want to provide demodata with timecodes:
As a result, a time code is stored in the system and thus always receives temporally relevant demo data, no matter when you create the demo data.

<field name="date_order" eval="(DateTime.today() - 
relativedelta(months=1)).strftime('%Y-%m-%d %H:%M')"/>

It is also possible to overwrite records that are always automatically created in Odoo. For example, Odoo always creates the company with YourCompany.
So we can just override them with the following record. First, we overwrite the res.partner and then the base.main_company, because it references the res.partner.

<!-- Company -->
     <record id="base.main_partner" model="res.partner" context="{'default_is_company': True}">
     <field name="name">bloopark systems GmbH &amp; Co. KG</field>
     <field name="company_id" eval="None" />
     <field name="image" eval="False" />
     <field name="customer" eval="False" />
     <field name="is_company" eval="True" />
     <field name="street">Sternstraße 8</field>
     <field name="city">Magdeburg</field>
     <field name="zip">39104</field>
     <field name="phone">+49(391)5630690</field>
     <field name="fax">+49(391)56306929</field>
     <field name="email">info@bloopark.de </field>
     <field name="website">www.bloopark.de</field>
            <field name="bank_ids" eval="[(6,0,[ref('bloopark_bank_account_1')])]" />
     </record>
     <record id="base.main_company" model="res.company">
     <field name="name">bloopark systems GmbH &amp; Co. KG</field>
     <field name="partner_id" ref="base.main_partner" />
     <field name="rml_header1">Nett working people</field>
     <field name="vat">DE259980759</field>
     <field name="company_registry">HRA 1980</field>
     <field name="currency_id" ref="base.EUR" />
            <field name="bank_ids" eval="[(6,0,[ref('bloopark_bank_account_1')])]" />
     <field name="logo" type="base64" file="bloopark/static/src/img/bloopark_logo.png" />
     <field name="custom_footer" eval="True" />
     <field name="rml_footer">
     Tel: +49(391)5630690 | Fax: +49(391)56306929 | E-Mail Adresse: info@bloopark.de | Website: www.bloopark.de |
                Amtsgericht Stendal: HRA 1980 
     </field>
     </record>

As we now realize, our Main Company needs more dependencies. This is very important and must be taken into account when creating demo data, as otherwise they will emit errors and not be transferred to the system.
So we do not have the bank id, that means we add our bank data to our demo data and realize that this implies a further dependency. This can happen quite often and you can then shimmy from bottom to top until all necessary dependencies are given.

<!-- Bank -->
     <record id="bloopark_bank_1" model="res.bank">
     <field name="active" eval="True" />
     <field name="name">Bank Name</field>
     </record>
     <!-- Bank Account -->
        <record id="bloopark_bank_account_1" model="res.partner.bank">
     <field name="bank" ref="bloopark_bank_1" />
     <field name="bank_name">Bank Name</field>
     <field name="bank_bic">Bic Nummer</field>
     <field name="state">iban</field>
     <field name="acc_number">Acc Nummer</field>
     <field name="partner_id" ref="base.main_partner" />
     <field name="journal_id" ref="base.EUR" />
     </record>
<!-- Company -->
     <record id="base.main_partner" model="res.partner" context="{'default_is_company': True}">
     <field name="name">bloopark systems GmbH &amp; Co. KG</field>
     <field name="company_id" eval="None" />
     <field name="image" eval="False" />
     <field name="customer" eval="False" />
     <field name="is_company" eval="True" />
     <field name="street">Sternstraße 8</field>
     <field name="city">Magdeburg</field>
     <field name="zip">39104</field>
     <field name="phone">+49(391)5630690</field>
     <field name="fax">+49(391)56306929</field>
     <field name="email">info@bloopark.de </field>
     <field name="website">www.bloopark.de</field>
            <field name="bank_ids" eval="[(6,0,[ref('bloopark_bank_account_1')])]" />
     </record>
     <record id="base.main_company" model="res.company">
     <field name="name">bloopark systems GmbH &amp; Co. KG</field>
     <field name="partner_id" ref="base.main_partner" />
     <field name="rml_header1">Nett working people</field>
     <field name="vat">DE259980759</field>
     <field name="company_registry">HRA 1980</field>
     <field name="currency_id" ref="base.EUR" />
            <field name="bank_ids" eval="[(6,0,[ref('bloopark_bank_account_1')])]" />
     <field name="logo" type="base64" file="bloopark/static/src/img/bloopark_logo.png" />
     <field name="custom_footer" eval="True" />
     <field name="rml_footer">
     Tel: +49(391)5630690 | Fax: +49(391)56306929 | E-Mail Adresse: info@bloopark.de | Website: www.bloopark.de |
                Amtsgericht Stendal: HRA 1980 
     </field>
     </record>

It is also possible to give dependencies to certain records via parent_id. Here we create three sales teams, two depending on the first one. This has the advantage that we create in a section dependency, over- and sub-categories.

<!-- Sales teams-->
     <record model="crm.case.section" id="crm.section_sales_department">
         <field name="name">Bloopark Gesamt</field>
         <field name="code"></field>
         <field name="user_id" ref="user_1" />
         <field name="stage_ids"
             eval="[
             (4, ref('crm.stage_lead1')),
             (4, ref('crm.stage_lead2')),
             (4, ref('crm.stage_lead3')),
             (4, ref('crm.stage_lead4')),
             (4, ref('crm.stage_lead5')),
             (4, ref('crm.stage_lead6')),
             (4, ref('crm.stage_lead7'))]" />
     </record>
     <record model="crm.case.section" id="lr_crm_case_section1">
         <field name="name">Bloopark Intern</field>
         <field name="code">Intern</field>
            <field name="parent_id" ref="crm.section_sales_department" />
         <field name="user_id" ref="user_1" />
         <field name="stage_ids"
             eval="[
             (4, ref('crm.stage_lead1')),
             (4, ref('crm.stage_lead2')),
             (4, ref('crm.stage_lead3')),
             (4, ref('crm.stage_lead4')),
             (4, ref('crm.stage_lead5')),
             (4, ref('crm.stage_lead6')),
             (4, ref('crm.stage_lead7'))]" />
     </record>
     <record model="crm.case.section" id="lr_crm_case_section2">
         <field name="name">Bloopark Extern</field>
         <field name="code">Extern</field>
            <field name="parent_id" ref="crm.section_sales_department" />
         <field name="user_id" ref="user_1" />
         <field name="stage_ids"
             eval="[
             (4, ref('crm.stage_lead1')),
             (4, ref('crm.stage_lead2')),
             (4, ref('crm.stage_lead3')),
             (4, ref('crm.stage_lead4')),
             (4, ref('crm.stage_lead5')),
             (4, ref('crm.stage_lead6')),
             (4, ref('crm.stage_lead7'))]" />
     </record>

About Benjamin Bachmann

The Mac expert and code maniac/ Recently started his path into the python and Odoo world/ Likes his coffee cold, but we love him anyway.