# Copyright 2026 Criptomart # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) from datetime import datetime from datetime import timedelta from odoo.exceptions import ValidationError from odoo.tests import tagged from odoo.tests.common import HttpCase from odoo.tests.common import TransactionCase class GroupOrderSlugCommon: """Helpers to build consumer group orders with the mandatory fields.""" def _create_group_order(self, name, **values): start_date = datetime.now().date() vals = { "name": name, "group_ids": [(6, 0, [self.group.id])], "type": "regular", "start_date": start_date, "end_date": start_date + timedelta(days=7), "period": "weekly", "pickup_day": "3", "cutoff_day": "0", } vals.update(values) return self.env["group.order"].create(vals) class TestGroupOrderSlug(GroupOrderSlugCommon, TransactionCase): """URL slug generation, normalization and validation.""" def setUp(self): super().setUp() self.group = self.env["res.partner"].create( { "name": "Slug Test Group", "is_company": True, "is_group": True, "email": "slug-group@test.com", } ) def test_slug_generated_from_name(self): order = self._create_group_order("Escola Fructuós Gelabert") self.assertEqual(order.slug, "escola-fructuos-gelabert") def test_slug_is_unique(self): first = self._create_group_order("Weekly Order") second = self._create_group_order("Weekly Order") self.assertEqual(first.slug, "weekly-order") self.assertEqual(second.slug, "weekly-order-2") def test_explicit_slug_is_normalized(self): order = self._create_group_order("Weekly Order", slug="Fructuós Gelabert") self.assertEqual(order.slug, "fructuos-gelabert") def test_slug_kept_when_name_changes(self): order = self._create_group_order("Weekly Order") order.name = "Renamed Order" self.assertEqual(order.slug, "weekly-order") def test_emptying_slug_regenerates_it(self): order = self._create_group_order("Weekly Order") order.write({"name": "Renamed Order", "slug": False}) self.assertEqual(order.slug, "renamed-order") def test_reserved_slug_is_avoided_on_generation(self): order = self._create_group_order("Labels") self.assertEqual(order.slug, "labels-eskaera") def test_reserved_slug_is_rejected(self): with self.assertRaises(ValidationError): self._create_group_order("Weekly Order", slug="save-order") def test_numeric_slug_is_rejected(self): with self.assertRaises(ValidationError): self._create_group_order("Weekly Order", slug="42") def test_name_without_slug_characters_falls_back(self): order = self._create_group_order("!!!") self.assertEqual(order.slug, "eskaera") @tagged("post_install", "-at_install") class TestGroupOrderSlugRoutes(GroupOrderSlugCommon, HttpCase): """The shop pages answer on the slug URL, the numeric one redirects.""" def setUp(self): super().setUp() # is_group matters: both `res.partner.group_ids` and # `group.order.group_ids` filter on it when they are read. self.group = self.env["res.partner"].create( { "name": "Slug Routes Group", "is_company": True, "is_group": True, "email": "slug-routes-group@test.com", } ) member = self.env["res.partner"].create( {"name": "Slug Routes Member", "email": "slug-routes-member@test.com"} ) self.group.member_ids = [(4, member.id)] login = "portal.slug.routes@test.com" self.env["res.users"].create( { "name": "Slug Routes User", "login": login, "password": login, "partner_id": member.id, "groups_id": [(4, self.env.ref("base.group_portal").id)], } ) self.portal_login = login self.group_order = self._create_group_order("Slug Routes Order") self.group_order.action_open() # The HTTP requests below share this transaction but not the ORM cache: # the many2many rows (group members, order groups) have to be in the # database before the controller reads them. self.env.flush_all() def test_slug_urls_answer(self): self.authenticate(self.portal_login, self.portal_login) for url in ( f"/eskaera/{self.group_order.slug}", f"/eskaera/{self.group_order.slug}/checkout", ): response = self.url_open(url, allow_redirects=False) self.assertEqual(response.status_code, 200, url) def test_numeric_urls_redirect_to_slug(self): self.authenticate(self.portal_login, self.portal_login) for url, expected in ( (f"/eskaera/{self.group_order.id}", f"/eskaera/{self.group_order.slug}"), ( f"/eskaera/{self.group_order.id}/checkout", f"/eskaera/{self.group_order.slug}/checkout", ), ): response = self.url_open(url, allow_redirects=False) self.assertIn(response.status_code, (301, 302, 303), url) self.assertTrue( response.headers.get("Location", "").endswith(expected), f"{url} should redirect to {expected}, " f"got {response.headers.get('Location')}", ) def test_unknown_slug_falls_back_to_the_list(self): self.authenticate(self.portal_login, self.portal_login) response = self.url_open("/eskaera/does-not-exist", allow_redirects=False) self.assertIn(response.status_code, (301, 302, 303)) self.assertTrue(response.headers.get("Location", "").endswith("/eskaera"))