From a9de1c0c1a82e0e92d95bdc0c93437104de843d8 Mon Sep 17 00:00:00 2001 From: japat-odoo Date: Thu, 19 Feb 2026 19:01:16 +0530 Subject: [PATCH] [ADD] zero_stock_approval: restriction on SO confirmation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new boolean field `zero_stock_approval` to sale.order to control whether a sales user is allowed to confirm orders with insufficient available stock. Sales users (non-managers) cannot confirm a sale order when stock is insufficient unless the approval checkbox is checked. Sales managers can always confirm regardless of the field value. This enforces business rules for zero stock approvals and keeps the confirmation logic consistent with access rights. The override of `action_confirm` checks each order line’s stock availability and prevents confirmation if conditions are not met. --- zero_stock_blockage/__init__.py | 1 + zero_stock_blockage/__manifest__.py | 10 ++++++++ zero_stock_blockage/models/__init__.py | 1 + zero_stock_blockage/models/sale_order.py | 23 +++++++++++++++++++ .../views/sale_order_views.xml | 18 +++++++++++++++ 5 files changed, 53 insertions(+) create mode 100644 zero_stock_blockage/__init__.py create mode 100644 zero_stock_blockage/__manifest__.py create mode 100644 zero_stock_blockage/models/__init__.py create mode 100644 zero_stock_blockage/models/sale_order.py create mode 100644 zero_stock_blockage/views/sale_order_views.xml diff --git a/zero_stock_blockage/__init__.py b/zero_stock_blockage/__init__.py new file mode 100644 index 00000000000..9a7e03eded3 --- /dev/null +++ b/zero_stock_blockage/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/zero_stock_blockage/__manifest__.py b/zero_stock_blockage/__manifest__.py new file mode 100644 index 00000000000..19f7bf1bf41 --- /dev/null +++ b/zero_stock_blockage/__manifest__.py @@ -0,0 +1,10 @@ +{ + "name": "zero_stock_blockage", + "author": "japat", + "license": "LGPL-3", + "depends": ["sale_management", "stock"], + "data": [ + "views/sale_order_views.xml", + ], + "auto_install": True, +} diff --git a/zero_stock_blockage/models/__init__.py b/zero_stock_blockage/models/__init__.py new file mode 100644 index 00000000000..6aacb753131 --- /dev/null +++ b/zero_stock_blockage/models/__init__.py @@ -0,0 +1 @@ +from . import sale_order diff --git a/zero_stock_blockage/models/sale_order.py b/zero_stock_blockage/models/sale_order.py new file mode 100644 index 00000000000..f0e71a5eb09 --- /dev/null +++ b/zero_stock_blockage/models/sale_order.py @@ -0,0 +1,23 @@ +from odoo import fields, models +from odoo.exceptions import AccessError + + +class SaleOrder(models.Model): + _inherit = ["sale.order"] + + zero_stock_approval = fields.Boolean(default=False, string="Approval") + + def action_confirm(self): + for record in self: + for line in record.order_line: + if ( + not record.zero_stock_approval + and not self.env.user.has_group("sales_team.group_sale_manager") + and line.product_id.type == "consu" + and line.product_id.is_storable + and line.product_id.qty_available < line.product_uom_qty + ): + raise AccessError( + "Access denied: You are not authorized to confirm this sales order." + ) + return super().action_confirm() diff --git a/zero_stock_blockage/views/sale_order_views.xml b/zero_stock_blockage/views/sale_order_views.xml new file mode 100644 index 00000000000..92cfb5603a1 --- /dev/null +++ b/zero_stock_blockage/views/sale_order_views.xml @@ -0,0 +1,18 @@ + + + + + sale.order.form.inherit.sale.new + sale.order + + + + + + + + + + +