[FIX] website_sale_aplicoop: three defects in the group order slug

- create(): slugs were only checked against the database, so records created
  in the same batch (duplicating several orders from the list view, importing
  rows sharing a name) collided on group_order_slug_uniq. _generate_unique_slug
  now also skips the slugs already handed out in the batch.
- _redirect_to_slug_url(): `post` is passed as a dict instead of splatted, so a
  query parameter named `suffix` no longer binds to the keyword argument of the
  same name (HTTP 500 on /eskaera/<id>/checkout?suffix=x, and a corrupted path
  on the shop route).
- post-migrate: the backfill runs with tracking_disable, `slug` is tracked and
  the upgrade posted a chatter message on every pre-existing order.

Tests for the two reachable cases: batch create and query parameters kept
across the legacy redirect.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
GitHub Copilot 2026-08-11 22:53:09 +02:00
parent 23edee6154
commit 157b344d4b
4 changed files with 65 additions and 20 deletions

View file

@ -398,14 +398,18 @@ class GroupOrder(models.Model):
domain.append(("id", "not in", self.ids))
return bool(self.sudo().search_count(domain, limit=1))
def _generate_unique_slug(self, name):
"""Build a free slug out of `name`, adding a counter when needed."""
def _generate_unique_slug(self, name, taken=()):
"""Build a free slug out of `name`, adding a counter when needed.
`taken` holds the slugs already handed out in the same batch, which are
not in the database yet and so are invisible to `_is_slug_taken`.
"""
base = self._normalize_slug(name)
if not base or base.isdigit() or base in RESERVED_SLUGS:
base = f"{base}-{DEFAULT_SLUG_BASE}" if base else DEFAULT_SLUG_BASE
candidate = base
counter = 2
while self._is_slug_taken(candidate):
while candidate in taken or self._is_slug_taken(candidate):
candidate = f"{base}-{counter}"
counter += 1
return candidate
@ -413,17 +417,15 @@ class GroupOrder(models.Model):
@api.model_create_multi
def create(self, vals_list):
"""Give every consumer group order a slug for its public URL."""
vals_list = [
dict(
vals,
slug=(
self._normalize_slug(vals.get("slug"))
or self._generate_unique_slug(vals.get("name"))
),
taken = set()
new_vals_list = []
for vals in vals_list:
slug = self._normalize_slug(vals.get("slug")) or self._generate_unique_slug(
vals.get("name"), taken=taken
)
for vals in vals_list
]
return super().create(vals_list)
taken.add(slug)
new_vals_list.append(dict(vals, slug=slug))
return super().create(new_vals_list)
def write(self, vals):
"""Normalize the slug, regenerating it from the name when emptied."""