Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions sale_exception/models/sale_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Copyright 2018 Akretion
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo.api import Environment
from odoo.modules.registry import Registry

from odoo import api, models

Expand Down Expand Up @@ -48,10 +50,18 @@ def sale_check_exception(self):
orders._check_exception()

def action_confirm(self):
if self.detect_exceptions():
if not self.env.company.sale_exception_show_popup:
return
return self._popup_exceptions()
breakpoint()
with Registry(self.env.cr.dbname).cursor() as new_cr:
new_env = Environment(new_cr, self.env.uid, self.env.context)
exception_ids = self.with_env(new_env).detect_exceptions()
if exception_ids:
new_cr.commit()

if exception_ids:
# FIXME: As ValidationError is raised, the client is not refreshed to
# display the exception summary. Should we catch the ValidationError
# and use another error class to force that?
self._check_exception()
return super().action_confirm()

def action_draft(self):
Expand Down
1 change: 1 addition & 0 deletions test_sale_exception_confirm/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
18 changes: 18 additions & 0 deletions test_sale_exception_confirm/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2025 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
{
"name": "Test sale exception confirm",
"summary": "Ensure any action in action confirm is rolled back upon exception",
"version": "18.0.1.0.0",
"category": "Uncategorized",
"website": "https://github.com/OCA/sale-workflow",
"author": "Camptocamp, Odoo Community Association (OCA)",
"maintainers": ["grindtildeath"],
"license": "AGPL-3",
"depends": [
"sale_exception",
],
"demo": [
"demo/sale_exception_demo.xml",
],
}
6 changes: 6 additions & 0 deletions test_sale_exception_confirm/demo/sale_exception_demo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="sale_exception.excep_no_free" model="exception.rule">
<field name="active" eval="True" />
</record>
</odoo>
1 change: 1 addition & 0 deletions test_sale_exception_confirm/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import sale_order
16 changes: 16 additions & 0 deletions test_sale_exception_confirm/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2025 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from odoo import fields, models


class SaleOrder(models.Model):
_inherit = "sale.order"

before_confirm = fields.Char()
after_confirm = fields.Char()

def action_confirm(self):
self.write({"before_confirm": "Write before confirm"})
res = super().action_confirm()
self.write({"after_confirm": "Write after confirm"})
return res
1 change: 1 addition & 0 deletions test_sale_exception_confirm/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_sale_exception_confirm
39 changes: 39 additions & 0 deletions test_sale_exception_confirm/tests/test_sale_exception_confirm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright 2025 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from odoo.fields import Command
from odoo.tests import TransactionCase


class TestSaleExceptionConfirm(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.no_free_exception = cls.env.ref("sale_exception.excep_no_free")
# cls.no_free_exception.active = True
cls.partner = cls.env.ref("base.res_partner_12")
cls.product = cls.env.ref("product.product_product_9")

def test_action_confirm_rollback(self):
sale_order = self.env["sale.order"].create(
{
"partner_id": self.partner.id,
"order_line": [
Command.create(
{
"product_id": self.product.id,
"name": self.product.name,
"product_uom_qty": 1.0,
"price_unit": 0.0,
},
)
],
}
)
self.assertFalse(sale_order.before_confirm)
self.assertFalse(sale_order.after_confirm)
self.assertTrue(self.no_free_exception.active)
sale_order.action_confirm()
self.assertEqual(sale_order.exception_ids, self.no_free_exception)
self.assertEqual(sale_order.state, "draft")
self.assertFalse(sale_order.before_confirm)
self.assertFalse(sale_order.after_confirm)
Loading