[ADD] user friendly error handling for restricted qty on ecommerce app
Some checks failed
pre-commit / pre-commit (pull_request) Has been cancelled

This commit is contained in:
2026-08-18 17:52:11 +02:00
parent a140edb60e
commit 5d8293f73e
10 changed files with 393 additions and 0 deletions

View File

@@ -0,0 +1 @@
from . import test_restricted_qty_website_sale

View File

@@ -0,0 +1,89 @@
from lxml import html
from odoo.exceptions import ValidationError
from odoo.tests import HttpCase, tagged
from odoo.addons.http_routing.models.ir_http import slug
@tagged("post_install", "-at_install")
class TestRestrictedQtyInfo(HttpCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.partner = cls.env["res.partner"].create({"name": "eCommerce customer"})
cls.product_min = cls._create_product(
"Product min 6", manual_sale_min_qty=6.0
)
cls.product_free = cls._create_product("Unrestricted product")
# force = Yes -> purely indicative bound, nothing to tell the customer
cls.product_indicative = cls._create_product(
"Product min 6 indicative",
manual_sale_min_qty=6.0,
manual_force_sale_min_qty="force",
)
@classmethod
def _create_product(cls, name, **restrictions):
values = {
"name": name,
"type": "consu",
"list_price": 10.0,
"sale_ok": True,
"is_published": True,
}
values.update(restrictions)
return cls.env["product.template"].create(values).product_variant_id
# ------------------------------------------------------------------
# Error message
# ------------------------------------------------------------------
def _create_line(self, product, qty):
order = self.env["sale.order"].create({"partner_id": self.partner.id})
self.env["sale.order.line"].create(
{
"order_id": order.id,
"product_id": product.id,
"product_uom_qty": qty,
}
)
# @api.constrains are evaluated on flush, not on create().
self.env.flush_all()
return order
def test_error_message_is_customer_facing(self):
with self.assertRaises(ValidationError) as error:
self._create_line(self.product_min, 1)
message = str(error.exception)
self.assertIn("Product min 6", message)
self.assertIn("6", message)
self.assertNotIn("force min", message, "Upstream jargon still present")
def test_valid_quantity_raises_nothing(self):
self._create_line(self.product_min, 6)
def test_indicative_minimum_still_does_not_block(self):
self._create_line(self.product_indicative, 1)
# ------------------------------------------------------------------
# Product page display
# ------------------------------------------------------------------
def _hint_on_page(self, product):
response = self.url_open("/shop/%s" % slug(product.product_tmpl_id))
self.assertEqual(response.status_code, 200)
tree = html.fromstring(response.content)
return tree.xpath("//div[contains(@class, 'o_wsale_qty_restriction')]")
def test_hint_is_displayed(self):
hint = self._hint_on_page(self.product_min)
self.assertEqual(len(hint), 1)
self.assertIn("6", hint[0].text_content())
def test_no_hint_without_restriction(self):
self.assertFalse(self._hint_on_page(self.product_free))
def test_no_hint_for_an_indicative_minimum(self):
self.assertFalse(self._hint_on_page(self.product_indicative))