Odoo modules are essential for adding or enhancing business logic within Odoo. Here, we’ll walk through creating a basic Odoo module in Odoo 17.
Module Structure
A typical Odoo module contains several key elements that are organized in a structured way. For a detailed look at the module structure, refer to the blog An Overview of Odoo 17 Module Structure.
Scaffolding a Module
Use the scaffold command to automatically generate the basic structure of a module:
./odoo-bin scaffold module_name custom_addons_location
Manifest File and Models
Create the manifest file (__manifest__.py), which includes the module details. Then, create a directory called models for storing Python models. Here’s an example model for a gym membership:
from odoo import api, fields, models, _
class GymMembership(models.Model):
_name = "gym.membership"
_description = "Gym Membership"
_rec_name = "reference"
reference = fields.Char(string='GYM reference', required=True,
readonly=True,default=lambda self: _('New'))
member_id = fields.Many2one('res.partner',string='Member',required=True,
tracking=True)
membership_scheme_id = fields.Many2one('product.product',
string='Membership scheme',
required=True, tracking=True)
paid_amount = fields.Integer(string="Paid Amount", tracking=True)
membership_fees = fields.Float(string="Membership Fees", tracking=True)
sale_order_id = fields.Many2one('sale.order', string='Sales Order',
ondelete='cascade', copy=False,
readonly=True)
membership_date_from = fields.Date(string='Membership Start Date',
help='Date from which membership becomes active.')
membership_date_to = fields.Date(string='Membership End Date',
help='Date until which membership remains active.')
company_id = fields.Many2one('res.company', string='Company', required=True,
readonly=True,
default=lambda self: self.env.company)
Add this model to the __init__.py file within the model's directory:
from . import membership
Ensure the module’s __init__.py includes:
from . import models
Defining Views with XML
To create a user interface, define the views in XML files. This includes menus and submenus, as well as the kanban, list, and form views. Here’s an example:
Model Action
<record id="action_gym_membership" model="ir.actions.act_window">
<field name="name">Gym Management</field>
<field name="res_model">gym.membership</field>
<field name="view_mode">tree,form</field>
</record>
Menus
<menuitem id="gym_management_root"
name="Gym Management"
sequence="10"/>
<menuitem id="membership_menu"
name="Membership"
sequence="1"
parent="gym_management_root"/>
<menuitem
id="menu_gym_membership"
name="Membership"
parent="membership_menu"
action="action_gym_membership"
sequence="1"/>
Tree and Form Views
<record id="view_membership_tree" model="ir.ui.view">
<field name="name">gym.membership.tree</field>
<field name="model">gym.membership</field>
<field name="arch" type="xml">
<tree default_order="reference desc">
<field name="reference"/>
<field name="member_id"/>
<field name="membership_scheme_id"/>
<field name="membership_fees"/>
</tree>
</field>
</record>
<record id="view_membership_form" model="ir.ui.view">
<field name="name">gym.membership.form</field>
<field name="model">gym.membership</field>
<field name="arch" type="xml">
<form>
<sheet>
<div class="oe_title">
<h1>
<field name="reference"/>
</h1>
</div>
<group>
<group>
<field name="member_id"/>
<field name="membership_scheme_id"/>
<field name="paid_amount"/>
</group>
<group>
<field name="membership_fees"/>
<field name="sale_order_id" readonly="1"/>
<label for="membership_date_from"
string="Membership Duration"/>
<div class="o_row">
<field name="membership_date_from"
required="1"/>
-
<field name="membership_date_to"
required="1"/>
</div>
</group>
</group>
</sheet>
</form>
</field>
</record>
Security
Add a security file to define access rights if necessary. Here’s an example:
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_gym_membership,account.gym.membership,model_gym_membership,base.group_user,1,1,1,1
Refer to Security Groups and Access Rights in Odoo 17 for more details.
Final Steps
Add the module path in the manifest file, navigate to Apps, and upgrade to see your custom module available.
Install the module, and you will now see it listed in the menu.
You will now see the Gym Management parent menu. Click on it to access the member submenu and other defined submenus.
The defined fields are displayed here. Please fill in the necessary details accordingly.
If you make any changes to the XML file, remember to upgrade the module. If you make any updates in Python, be sure to restart the service.
To include an icon for the module, place the icon.png file in the static/description/ directory.
The manifest file contains the details displayed in the module information.
This approach allows you to create and modify modules in Odoo 17.