Author Archive

OpenERP Custom Sample Module Development – OpenERP Quick Start Guide

Posted on: January 3rd, 2011 by Keerthi Bandara 2 Comments

Introduction

This article will explain the basic steps involved in developing custom OpenERP modules. It is a “Hello World” kind of guideline, therefore you won’t be able to find out all the theories behind OpenObject platform here. Instead you will get all the necessary information to get started with. Sample module given here is fully functional and tested on OpenERP version 6.0-RC2 (with Web Client on Chrome browser). You will be able to download the complete source code at the end of this article.

Module Description

The sample module we are going to develop is a simple Notebook application. It helps to take down notes and contains just three fields namely “Title”, “Note” and “Date” in its data model.

Module Structure

An OpenERP module consists of some basic elements as explained below. Note that what is explained here is only the basic files required and structure will be more complex in real world applications.
  • module_name.py – contains the application logic and database table structure definition.
  • __init__.py – init script will load the application’s main python-module and related in application initialization.
  • view_name.xml – contains the application interface definition and menu structure.
  • __openerp__.py – is the module descriptor file. In previous versions of OpenERP this was known as “__terp__.py”

File Contents

Even though there is no specific order, I am going to start with the main python class (module) of our OpenERP module. This will handle the core functionality of the module and also will generate the database table to store related data.

[ notebook.py ]

[python] from osv import fields, osv import time class notebook(osv.osv): _name = "notebook" _description = "Simple Notebook" _columns = { ‘title’ : fields.char(‘Title’, size=30, required=True), ‘note’ : fields.text(‘Note’), ‘note_date’ : fields.date(‘Date’), } notebook() [/python] Next we import the python module we created in application initialization script.

[ __init__.py ]

[python] import notebook [/python] After that we define the view and menu structure of our module.

[ notebook_view.xml ]

[xml] <?xml version="1.0" encoding="utf-8"?> <openerp> <data> <record model="ir.ui.view" id="notebook_tree_view"> <field name="name">notebook.tree</field> <field name="model">notebook</field> <field name="type">tree</field> <field name="arch" type="xml"> <tree string="Notebook"> <field name="title"/> <field name="note"/> <field name="note_date"/> </tree> </field> </record> <record model="ir.ui.view" id="notebook_form_view"> <field name="name">notebook.form</field> <field name="model">notebook</field> <field name="type">form</field> <field name="arch" type="xml"> <form string="Notebook"> <field name="title"/> <field name="note"/> <field name="note_date"/> </form> </field> </record> <record model="ir.actions.act_window" id="action_notebook_form"> <field name="name">notebook</field> <field name="res_model">notebook</field> </record> <menuitem name="Notebook" icon="terp-project" id="notebook_menu"/> <menuitem name="Notes" parent="notebook_menu" id="notebook_menu_mainform" action="action_notebook_form"/> </data> </openerp> [/xml] Finally create the application descriptor as follows.

[ __openerp__.py ]

[python] { "name" : "notebook", "version" : "0.1", "author" : "Keerthi Bandara @ iBCScorp", "website" : "http://www.ibcscorp.com/", "category" : "Generic Modules/Others", "depends" : ["base"], "description" : "Simple demo module", "init_xml" : ["notebook_view.xml"], "demo_xml" : [], "update_xml" : [], "active": False, "installable": True } [/python]

Packaging and Installing New Module

To prepare your module for installation, you may simply compress the module directory into a zip archive (e.g. notebook.zip). Once your module archive is ready, you can continue the installation by following the given path below. 1. Login to OpenERP admin view and open “Import Module” screen under “Modules” section in “Administration” area.  Select newly created module archive and click “Import Module” button. Note: Sometimes on OpenERP V6 (RC2), the message ”Loading..” will be continuously displayed, even though your module is successfully imported. In that case simply close the message window and continue to next step. 2. After importing new module, it will appear under OpenERP “Modules” list. It can be easily located by Searching for the module name. Once you found the module, mark it for installation, then select the check box in front of the module and click “Apply Scheduled Upgrades” link. Click on “Start update” to continue the installation.

Accessing Your Module

After installing your module successfully, it will appear on the home screen of your OpenERP client as follows.
The sample source code explained above is available here.

Conclusion

Motivation behind preparing this article was the difficulty I have faced in finding out a proper start up guide in custom OpenERP module development. Even official documentation appeared to be incomplete/inconsistent at the moment of writing this article.
Anyway there is a lot more to explore in OpenERP module development. As an OpenERP partner, iBCScorp is always willing to help you in your OpenERP implementation project. If you found this post useful just leave a comment and do not hesitate to contact us on any OpenERP related issue.

CakePHP Samples

Posted on: December 2nd, 2010 by Keerthi Bandara 1 Comment
This post provides some sample source code segment, extracted from our previously developed systems. The intention here is to depict the coding practices we apply within iBCScorp. Samples given below are based on CakePHP MVC framework. iBCScorp has involved in CakePHP development since the version 1.1. After that we have continued with 1.2.x releases and then absorbed 1.3.x releases into our developments later on. iBCScorp started using CakePHP 1.3 in projects since its pre-stable releases. Adopting the new version early helped iBCScorp to keep its source code clean and tight with new syntactical improvements, while avoiding version upgrades in near future. FreedomTravel4You.com is one of the sites built on CakePHP 1.3. Following code segment is extracted from its codebase. (agent_tree_controller.php). [php] <?php /** * Short description for file * This file handles the Agent Tree View functionality * * PHP versions > 5.0, CakePHP versions > 1.3 * * @package FreedomTravel4You.com * @author iBCScorp. * @copyright iBCScorp. * @license As described below * @version 1.0.0 * @since File available since Release 1.1.0 dt. Friday, 04 December, 2009 */ /********************************************************* * Licence: * This file is sole property of the installer. * Any type of copy or reproduction without the consent * of owner is prohibited. * If in any case used leave this part intact without * any modification. * All Rights Reserved * Copyright 2009 Owner *******************************************************/ class AgentTreeController extends AppController { var $name = ‘AgentTree’; var $uses = array(‘User’, ‘UserTree’); var $components = array(‘Auth’); var $helpers = array(‘Html’, ‘Javascript’, ‘TreeView’); function beforeFilter() { if($this->Session->read(‘user_info.admin’)){ $this->set(‘menu_type’, ‘admin’); } else { $this->set(‘menu_type’, ‘agent’); } $this->set(‘show_side_bar’, 0); } function index($element_id = null) { $this->common_tree_info($element_id); $this->set(‘page_title’, ‘Agent’); } // Action to display unassigned users for logged in agent function assign_agent() { $curr_user_id = $this->Session->read(‘Auth.User.id’); $unassigned_childrens = $this->User->get_unassigned_children($curr_user_id); $this->set(‘unassigned_childrens’, $unassigned_childrens); $this->set(‘page_title’, ‘Agent’); } // Display tree view to assign new agents to tree function add_to_tree($element_id = null) { $new_child_id; if(isset($this->params['form']['child_id'])){ $new_child_id = $this->params['form']['child_id']; // Store selected child-id to be assigned to tree $this->Session->write(‘child_to_be_assigned’, $new_child_id); } elseif($this->Session->check(‘child_to_be_assigned’)) { $new_child_id = $this->Session->read(‘child_to_be_assigned’); } else { $this->redirect(‘/agent_tree/assign_agent’); exit(0); } // get the child name for particular id $new_child_info = $this->User->find(‘first’, array( ‘conditions’ => array(‘id’ => $new_child_id), ‘fields’ => array(‘first_name’) )); // Call the common function to initialize tree $this->common_tree_info($element_id); $this->set(‘new_agent_name’, $new_child_info['User']['first_name']); $this->set(‘page_title’, ‘Agent’); } // Funtion to apend child to tree (last step) function append_child() { $child = explode("_", trim($this->params['form']['child_id'])); $tree_data = array(); $tree_data['UserTree']['parent_id'] = $child[0]; $tree_data['UserTree']['child_position'] = $child[1]; $tree_data['UserTree']['child_id'] = $child[2]; // Tree ID of the new Agent $this->UserTree->create(); $this->UserTree->save($tree_data); $new_user_id = $this->Session->read(‘child_to_be_assigned’); $this->User->id = $new_user_id; $this->User->saveField(‘tree_id’, $child[2]); $this->redirect(‘/agent_tree/index’); exit(0); } // Common function to initialize tree view. private function common_tree_info($element_id = null) { // Get user tree ID $curr_user_id = $this->Session->read(‘Auth.User.id’); $curr_user_info = $this->User->find(‘first’, array( ‘conditions’ => array(‘id’=> $curr_user_id), ‘fields’ => array(‘first_name’, ‘tree_id’, ‘parent_available’) )); // If this user is not yet appended to the tree disable this functionality if($curr_user_info['User']['parent_available'] == 0) { $this->redirect(‘/agent_tree/user_not_assigned’); exit(0); } $tree_id = ”; // tree id of the current root node // Get the user info for root element i.e. logged in or requested if(isset($element_id)){ $tree_id = $element_id; } else { $tree_id = $curr_user_info['User']['tree_id']; } $root_info = $this->User->get_root_node_info($tree_id); //reference_id of the current user or requested root element $this->set(‘root_reference_id’, $root_info['u']['reference_id']); // first name of the current root element $root_name = $root_info['u']['first_name'] . ‘ ‘ . $root_info['u']['last_name']; $this->set(‘root_name’, $root_name); //id of the current root node $this->set(‘root_id’, $root_info['u']['id']); //logged in user’s id $this->set(‘user_id’, $curr_user_id); //tree_id of the current user or requested root element $this->set(‘root_node’, $root_info['u']['tree_id']); // Used to display move up link $this->set(‘up_level_id’, $root_info['t']['parent_id']); } // Action to display on tree view, when logged in user is not assigned to the tree function user_not_assigned() { $this->set(‘page_title’, ‘Agent’); } function search_agent() { $this->layout = ‘ajax’; Configure::write(‘debug’, 0); $search_value = trim($this->params['named']['q']); // Check the type of search criteria $search_type = ”; // Check whether it is an email if(stripos($search_value, ‘@’) !== FALSE) { $search_type = ‘TYPE_EMAIL’; } elseif (!is_numeric(substr($search_value, 0 , 2)) && is_numeric(substr($search_value, 2 , 6))){ // Check for reference number $search_type = ‘TYPE_REF’; } else { // Value is a name $search_type = ‘TYPE_NAME’; } $conditions = array(); // Check whether email or reference # to be searched if($search_type == ‘TYPE_REF’) { // ref # $conditions['and'] = array( ‘reference_id’ => $search_value, ‘tree_id not’ => ‘NULL’ ); } elseif($search_type == ‘TYPE_EMAIL’) { // email $conditions['and'] = array( ‘email’ => $search_value, ‘tree_id not’ => ‘NULL’ ); } elseif($search_type == ‘TYPE_NAME’) { $conditions['and'] = array( ‘or’ => array(‘first_name like’ => ‘%’ . $search_value . ‘%’, ‘last_name like’ => ‘%’ . $search_value . ‘%’ ), ‘tree_id not’ => ‘NULL’ ); } $result = $this->User->find(‘all’, array( ‘fields’ => array(‘reference_id’, ‘first_name’, ‘last_name’, ‘email’, ‘tree_id’), ‘conditions’ => $conditions )); $output = ""; if(sizeof($result)) { foreach($result as $r) { $output .= $r['User']['tree_id'] . "|" . $r['User']['first_name'] . " " . $r['User']['last_name'] . "|" . $r['User']['email'] . "|" . $r['User']['reference_id']; $output .= ‘^’; } $output = rtrim($output, ‘^’); // Removing the trailing ^ character at the end of output text } else { $output = "NO"; } $this->set(‘search_result’, $output); } } ?> [/php]

OpenERP : Customizing Task View – Project Management Module

Posted on: September 3rd, 2010 by Keerthi Bandara No Comments

Adding Task Creator to Project / Task View

OpenERP Project Management module provides great set of features in managing daily tasks within the organization. By default, the Task Detail page does not display the person who created the task. As the task assigner, it is really important to identify the person who has created/assigned a particular task. With the OpenERP’s rich support/flexibility in customizations, this can be resolved in no time. (more…)

Determine the best way to automate Sitemaps

Posted on: November 16th, 2009 by Keerthi Bandara No Comments
In simple terms, a sitemap (or site map) is a list of all the pages in your website. Sitemaps provide two benefits: easier navigation (for visitors of your site) and better visibility by search engines. With the rise of modern SEO techniques the importance of the sitemap has been growing. Sitemaps are the best way to inform search engines about changes on your website. As a development company, we always apply current SEO techniques on our customer’s websites to ensure that they get top ranking on search engines. Not only on Google, but Yahoo, Bing and Ask.com etc. as well. Including sitemaps is one of the important tasks we perform when developing sites for our clients. And this is done either manually or dynamically according to the customer needs. Typically a good site with lots of content changes regularly. In this case it is expensive and tedious to continually update the site map. For this reason, we feel that in some cases it is important to be able to auto generate a sitemap. We evaluated some sitemap auto generating tools and following are some of the solutions we like: It is obvious that selecting a sitemap generating mechanism is depending on several facts such as the nature of the site, sever side technology used etc. So making the correct decision is up to your experience in SEO and web development team. Contact us if you would like help generating a sitemap for your site, have general web marketing, seo, or web design questions…