Customizing existing modules in OpenERP 7.0

Getting started on OpenERP can be a bit difficult, but when you get familiar with OpenERP API, you will be able to develop any new feature easily. Following this post, you’ll learn how to customize existing modules by adding new fields and extending existing views.

First of all, you should have a development environment. If you didn’t have one, you can check out this tutorial here. Once the database is created, go to Settings > Modules > Apps, and install the Timesheets application.

When the installation is finished, click on the Human Ressource menu, then on Timesheet activities view and click on create button, you will get the below view.

Default Timesheet Activities Tree View

We will go throught steps involved to obtain the below view:

expected_timesheet_activities_view

1. Create hr_timesheet_performance module

A basic module, is a python package containning an __openerp__.py file which declare the module definition. In our case, put inside it the following:

# -*- coding: utf-8 -*-
{
    'name': "Timesheet Performance",
    'version': "0.1",
    'author': "Wael BEN ZID",
    'category': "Tools",
    'depends': ['hr_timesheet_sheet'],
    'data': [],
    'demo': [],
    'installable': True
}

2. Update module list

Now go to Settings > Update module list and click on Update button, this will refresh the system module cache. If you didn’t see the Update module list sub-menu, this is because you have not Technical features permission. So go to Settings > Users and edit your account. Enable the Technical features check-box under usability. Finally, refresh your browser.

enable_technical_features

3. Install module

Now, go to Settings > Modules > Apps, search for Timesheet Improvement module and install it.

4. Extends the OpenObject model

Now lets extends the model by adding new fields. So create a hr_timesheet_performance.py file and put the following:

# -*- coding: utf-8 -*-

from openerp.osv import fields, osv

class hr_analytic_timesheet_performance(osv.Model):
    _inherit = "hr.analytic.timesheet"

    _columns = {
        "hour_start": fields.float("De"),
        "hour_end": fields.float("Au")
    }

    _defaults = {
        "hour_start": 8,
        "hour_end": 9
    }

hr_analytic_timesheet_performance()

In the first line, we import the required classes, then we will create our class which will extends the hr.analytic.timesheet model, by telling OpenObject that our class will inherits from it

_inherit = "hr.analytic.timesheet"

This is the real magic in OpenObject ORM, then we will define new fields on _columns attribute. Finally, I defined some default values for the new field in the _defaults attribute. I set hour_start to 8 (you will see 08:00 in the interface), and hour_end to 9.

Now, we should tell OpenERP to load the new model definition, so add the below line in hr_timesheet_performance/__init__.py

import hr_timesheet_performance

5. Extends the default view

Now, lets update the UI (OpenERP view), So, create a new file called hr_timesheet_performance_view.xml and put the following:


<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>

<record model="ir.ui.view" id="pv_performance_timesheet">
  <field name="name">hr.analytic.timesheet.performance.tree</field>
  <field name="model">hr.analytic.timesheet</field>
  <field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_tree" />
  <field name="arch" type="xml">
    <field name="account_id" position="after">
      <field name="hour_start" widget="float_time" />
      <field name="hour_end" widget="float_time" />
    </field>
  </field>
</record>

</openerp>
</data>

I defined a view called hr.analytic.timesheet.performance.tree which will use hr.analytic.timesheet as a model and inherits from the default view:

<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_tree" />

In this view, we will add hour_start and hour_end fields and use a float_time widget for both of them after the field account_id

<field name="account_id" position="after">
    <field name="hour_start" widget="float_time" />
    <field name="hour_end" widget="float_time" />
</field>

We should now tell OpenERP to load this view when it try to install/upgrade the module, So update data list in __openerp__.py file:

'data': ["hr_timesheet_performance_view.xml"],

So we will obtain the final module descriptor below:

# -*- coding: utf-8 -*-
{
    'name': "Timesheet Performance",
    'version': "0.1",
    'author': "Wael BEN ZID",
    'category': "Tools",
    'depends': ['hr_timesheet_sheet'],
    'data': ["hr_timesheet_performance_view.xml"],
    'demo': [],
    'installable': True
}

6. Upgrade module

Now, go to Settings > Apps> Installed Modules, select Timesheet Improvement module and upgrade it.

Once it’s done, go to the Timesheet Activities view, and you’ll see something like that:

new_timesheet_activities_view

 

What’s next ?

Now, I think that you found that development in OpenERP is not difficult. I hope that this tutorial has been helpful. In the next post, I’ll show you how to implement buisness logic.

What’s new in Python 3.x

In this post, you will take a tour at most of Python 3.x new features compared to Python 2.7.

1. print function

The print statement has been removed from Python 3.x, and replaced by the print function.

>>> # This is a python 3.x interpreter
>>> print("Hello World!")
Hello World!
>>> print("Hello", "World!")
Hello World!
>>> print "Hello World!"
File "", line 1
 print "Hello World!"

SyntaxError: invalid syntax

2. Integer division

In Python 2.x, the / operator is used for integer division, and real division should made explicitly. So only float(5)/3 or 5.0/3 returns the real division of 5 by 3. Python 3.x removes this confusing by limiting / operator to real division and // to integer division.

>>> # This is a python 3.x interpreter
>>> print (3 / 2)
1.5
>>> print (3 // 2)
1
>>> print ( 3/ 2.0)
1.5
>>> print ( 3 // 2.0)
1.0

3. Unicode

Finally, Python 3.x removes ASCII string types. So there is no such thing as a Python string encoded in ASCII (with str built-in) or in UTF-8. Now, in Python 3.x we have 2 kind of types str for text and bytes for binary data.  As a consequence of this change in philosophy:

  • We can not use u”…” litterals for unicode text. However, we should use b”…” for binary data
  • Encoded unicode is represented in binary data

4. range

Hopefuly, range returns now an iterable object instead of list, just like xrange in Python 2.x

5. Comparaison

In Python 2.x, we can compare unorderable types:

>>> # This is a python 2.x interpreter
>>> [1, 2] > "foo"
False
>>> (1, 2) > "bar"
True

However Python 3 throws a TypeError to avoid subtle bugs

>>> # This is a python 3.x interpreter
>>> 1 > "two"
TypeError: unorderable types: int() > str()

6. yield from

Python 3 arrives with the yield from expression, which permits generator delegation to subgenerators or arbitrary subiterators. So, instead of writing

>>> # This is a python 2.x interpreter
>>> for i in gen():
...     yield i

we can just write:

>>> # This is a python 3.x interpreter
>>> yield from gen():

This is much pretty and shortest: just in one line

7. Annotation

PEP 3107 introduced function annotations in Python. Here is a small example:

>>> # This is a python 3.x interpreter
>>> def greet(name: str):
...     print ("Hello {0}".format(name))

Prior to Python 3, Developers use 3rd-party libraries to annotate function, below an example

def greet(name):
    """
    Print a greet message
    :type name: str
    :param name: The name of person to be greeted.
    """
    print "Hello %s" % name

You can see that this method has some drawbacks: First of all, it does not respect DRY principle, second It’s not normalized because there are several docstring formats (sphinx, epydoc, etc.).

As you see, there are many great new features in Python 3.x, and may be you share with me that it’s time to change and upgrade to Python 3.

Its-Time-to-Change