The efficiency and precision with which approvals take place can often determine how operable the business is. Thus, Odoo 19 has made the supervision of multi-level approval processes extremely straightforward. The systematic process of approval guarantees that every transaction gets the necessary approval from a competent individual on time, be it an order for purchase, an HR paper, or a request for a budget.
This blog gives a detailed guidance on the automation of a multi-stage approval process in Odoo 19 by mentioning a real-life development example.
Why is it Important to Have Multiple Levels of Approval?
Many businesses can no longer do one-step approvals for their important transactions.
An example might be:
- Step 1 (Manager): Checks if the transaction is actually necessary.
- Step 2 (Director): Makes sure the costs are not overrunning the budget.
- Step 3 (Accounting): Makes the transaction and pays the necessary costs.
Automating a multi-step approval process reduces manual work, eliminates roadblocks, and provides an effective audit trail. The need for manual work gets rid of bottlenecks, and leaves a clear trail for audits.
Step 1: Define the Model and Approval Logic
First, we need to make a model that shows how to move between different states and what makes them work. We'll use a general "Document Approval" scenario.
from odoo import models, fields, api
from odoo.exceptions import UserError
class DocumentApproval(models.Model):
_name = 'document.approval'
_description = 'Multi-Step Document Approval'
_inherit = ['mail.thread', 'mail.activity.mixin']
name = fields.Char(string='Document Name', required=True, tracking=True)
amount = fields.Float(string='Amount', tracking=True)
state = fields.Selection([
('draft', 'Draft'),
('to_approve', 'Waiting Manager'),
('director_approve', 'Waiting Director'),
('approved', 'Approved'),
('refused', 'Refused'),
], default='draft', string='Status', tracking=True)
def action_submit(self):
"""Submit the document for first level approval."""
self.write({'state': 'to_approve'})
def action_manager_approve(self):
"""Managerial approval step."""
for rec in self:
if rec.amount > 5000:
rec.state = 'director_approve'
else:
rec.state = 'approved'
rec.message_post(body="Manager has approved this request.")
def action_director_approve(self):
"""Final Director approval."""
self.write({'state': 'approved'})
self.message_post(body="Director has granted final approval.")
def action_refuse(self):
"""Refusal logic."""
self.write({'state': 'refused'})
self.message_post(body="Request has been refused.")
Step 2: Define User Groups and Security
We need to set up security groups to lock down the approval steps. The manager approval button and other buttons should only be visible to people in the "Manager" group.
security/security.xml
<odoo>
<record model="res.groups.privilege" id="privilege_doc_approval">
<field name="name">Document Approval</field>
<field name="category_id" ref="base.module_category_human_resources"/>
</record>
<record id="group_doc_approval_manager" model="res.groups">
<field name="name">Document Approval Manager</field>
<field name="privilege_id" ref="privilege_doc_approval"/>
</record>
<record id="group_doc_approval_director" model="res.groups">
<field name="name">Document Approval Director</field>
<field name="privilege_id" ref="privilege_doc_approval"/>
</record>
</odoo>
Step 3: Create the User Interface (Views)
The last thing is to make the XML views. We'll use the statusbar component and buttons that only show up when certain conditions are met.
views/document_approval_views.xml
<record id="view_document_approval_form" model="ir.ui.view">
<field name="name">document.approval.form</field>
<field name="model">document.approval</field>
<field name="arch" type="xml">
<form>
<header>
<button name="action_submit" string="Submit" type="object"
invisible="state != 'draft'" class="btn-primary"/>
<button name="action_manager_approve" string="Approve" type="object"
invisible="state != 'to_approve'" groups="your_module.group_doc_approval_manager"
class="btn-primary"/>
<button name="action_director_approve" string="Final Approve" type="object"
invisible="state != 'director_approve'" groups="your_module.group_doc_approval_director"
class="btn-primary"/>
<button name="action_refuse" string="Refuse" type="object"
invisible="state in ('approved', 'refused')"/>
<field name="state" widget="statusbar" statusbar_visible="draft,to_approve,approved"/>
</header>
<sheet>
<group>
<field name="name"/>
<field name="amount"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
</record>
You can make a strong automation flow in Odoo 19 by following these three easy steps: defining the logic, securing the actions, and designing the UI. This not only makes your business processes more professional, but it also makes that every step is written down and approved.
Automating multi-step approvals is a small change that makes a big difference in how open and efficient operations are.
To read more about How to Configure Simple and Approval Workflows in Odoo 19, refer to our blog How to Configure Simple and Approval Workflows in Odoo 19.