In Odoo 15, confirming a sales order automatically creates a delivery order. While this default behavior works for many businesses, it can be limiting for organizations that require tighter operational control. Warehouses with complex workflows, approval processes, or external logistics dependencies often prefer to decide exactly when delivery notes are generated.
This article explains how to build a custom Odoo 15 module that disables automatic delivery creation and introduces a manual “Create Delivery” button on the sales order form. You will learn how to extend core models, adjust confirmation logic, customize views, and use context flags to manage stock picking generation.
Why Use Manual Delivery Notes in Odoo?
Consider a high-volume warehouse that processes hundreds of confirmed sales orders each day. Automatically generating delivery orders for every confirmation can overwhelm warehouse staff and complicate picking operations. A manual approach allows teams to review confirmed orders first and create delivery notes in controlled batches.
Another common scenario involves businesses that sell both stocked items and products that are manufactured or purchased on demand. These companies may need to confirm sales orders immediately for financial or reporting reasons, while postponing delivery creation until inventory is physically available.
Manual delivery note control allows Odoo to adapt to these workflows by separating sales confirmation from inventory execution.
Technical Approach Overview
The solution is based on three core components:
- Model Extensions: New computed fields are added to the
sale.ordermodel, and confirmation behavior is modified to prevent automatic stock rule execution. - View Customization: A custom action button is added to the sales order form to allow manual delivery creation when conditions are met.
- Context Flags: Odoo’s context mechanism is used to control when procurement and stock rules should be triggered.
This approach integrates cleanly with standard Odoo functionality, adding flexibility without breaking existing processes.
Step-by-Step Implementation
Step 1: Create the Module Structure
Start by creating a new custom module in your Odoo addons directory. The module should follow a standard structure:
manual_delivery/
├── __init__.py
├── __manifest__.py
├── models/
│ ├── __init__.py
│ └── sale_order.py
└── views/
└── sale_order_views.xmlThe manifest file defines the module metadata and dependencies required for proper operation:
{
'name': 'Manual Delivery Note Control',
'version': '1.0',
'category': 'Sales',
'author': 'Your Company',
'depends': ['sale', 'stock', 'sale_stock'],
'data': [
'views/sale_order_views.xml',
],
'installable': True,
'auto_install': False,
}Step 2: Extend the Sale Order Model
Extend the sale.order model to determine when manual delivery creation is allowed. This logic ensures that delivery notes can only be created for confirmed orders without active pickings.
from odoo import models, fields, api, _
from odoo.exceptions import UserError
import logging
_logger = logging.getLogger(__name__)
class SaleOrder(models.Model):
_inherit = 'sale.order'
manual_delivery_allowed = fields.Boolean(
string="Manual Delivery Allowed",
compute='_compute_manual_delivery_allowed',
store=True
)
manual_delivery_created = fields.Boolean(
string="Manual Delivery Created",
default=False,
copy=False
)
@api.depends('state', 'picking_ids.state')
def _compute_manual_delivery_allowed(self):
for order in self:
if order.state not in ('sale', 'done'):
order.manual_delivery_allowed = False
else:
active_pickings = order.picking_ids.filtered(
lambda p: p.state not in ('cancel', 'done')
)
order.manual_delivery_allowed = not bool(active_pickings)Step 3: Prevent Automatic Delivery Creation
Override the sales order confirmation method to stop Odoo from creating delivery orders automatically. A context flag is passed to signal that stock rules should be skipped.
def action_confirm(self):
return super(
SaleOrder,
self.with_context(skip_auto_delivery=True)
).action_confirm()Step 4: Add Manual Delivery Creation Logic
This method validates the sales order, checks for existing deliveries, prepares procurement groups if needed, and manually triggers stock rules.
def create_delivery_note_manually(self):
for order in self:
if order.state not in ('sale', 'done'):
raise UserError(_('Only confirmed orders can create deliveries.'))
existing_pickings = order.picking_ids.filtered(
lambda p: p.state not in ('cancel', 'done')
)
if existing_pickings:
raise UserError(_('Active delivery orders already exist.'))
if not order.procurement_group_id:
vals = order._prepare_procurement_group_vals()
order.procurement_group_id = self.env['procurement.group'].create(vals)
deliverable_lines = order.order_line.filtered(
lambda l: l.product_id
and l.product_id.type == 'product'
and l.product_uom_qty > 0
)
if not deliverable_lines:
raise UserError(_('No deliverable products found.'))
deliverable_lines.with_context(
manual_delivery_override=True
)._action_launch_stock_rule()
return {'type': 'ir.actions.client', 'tag': 'reload'}Step 5: Control Stock Rule Execution
Extend sale.order.line to ensure stock rules are executed only when manual delivery creation is explicitly triggered. Buy routes remain unaffected so that purchase orders continue to generate automatically.
Step 6: Add the Sales Order Button
The final step is to update the sales order form view and add a “Create Delivery” button that appears only when manual delivery creation is allowed.
Testing the Customization
After installing the module, confirm a sales order and verify that no delivery is created automatically. The manual delivery button should appear once the order is confirmed. Clicking the button should generate a single delivery order and hide the button afterward.
Test edge cases such as service-only orders, duplicate delivery attempts, and Buy-route products to ensure expected behavior.
Conclusion
Manual delivery note control in Odoo 15 provides businesses with precise control over inventory operations. By separating sales confirmation from delivery creation, organizations can adapt Odoo to complex warehouse workflows while maintaining compatibility with standard functionality.