Group cart overview by market, show market name on cards
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 52s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 52s
A page can have multiple markets — the overview now groups cart items by market_place_id instead of page. Each card shows the market name as heading with the page title below it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -60,12 +60,13 @@ async def get_calendar_entries_for_page(session, post_id: int):
|
|||||||
async def get_cart_grouped_by_page(session) -> list[dict]:
|
async def get_cart_grouped_by_page(session) -> list[dict]:
|
||||||
"""
|
"""
|
||||||
Load all cart items + calendar entries for the current identity,
|
Load all cart items + calendar entries for the current identity,
|
||||||
grouped by owning page (post_id).
|
grouped by market_place (one card per market).
|
||||||
|
|
||||||
Returns a list of dicts:
|
Returns a list of dicts:
|
||||||
{
|
{
|
||||||
"post": Post | None,
|
"post": Post | None,
|
||||||
"page_config": PageConfig | None,
|
"page_config": PageConfig | None,
|
||||||
|
"market_place": MarketPlace | None,
|
||||||
"cart_items": [...],
|
"cart_items": [...],
|
||||||
"calendar_entries": [...],
|
"calendar_entries": [...],
|
||||||
"product_count": int,
|
"product_count": int,
|
||||||
@@ -75,6 +76,7 @@ async def get_cart_grouped_by_page(session) -> list[dict]:
|
|||||||
"total": float,
|
"total": float,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Calendar entries (no market concept) attach to a page-level group.
|
||||||
Items without a market_place go in an orphan bucket (post=None).
|
Items without a market_place go in an orphan bucket (post=None).
|
||||||
"""
|
"""
|
||||||
from .get_cart import get_cart
|
from .get_cart import get_cart
|
||||||
@@ -85,31 +87,50 @@ async def get_cart_grouped_by_page(session) -> list[dict]:
|
|||||||
cart_items = await get_cart(session)
|
cart_items = await get_cart(session)
|
||||||
cal_entries = await get_calendar_cart_entries(session)
|
cal_entries = await get_calendar_cart_entries(session)
|
||||||
|
|
||||||
# Group by container_id (all current data has container_type="page")
|
# Group cart items by market_place_id
|
||||||
groups: dict[int | None, dict] = defaultdict(lambda: {
|
market_groups: dict[int | None, dict] = {}
|
||||||
"post_id": None,
|
|
||||||
"cart_items": [],
|
|
||||||
"calendar_entries": [],
|
|
||||||
})
|
|
||||||
|
|
||||||
for ci in cart_items:
|
for ci in cart_items:
|
||||||
if ci.market_place and ci.market_place.container_id:
|
mp_id = ci.market_place_id if ci.market_place else None
|
||||||
pid = ci.market_place.container_id
|
if mp_id not in market_groups:
|
||||||
else:
|
market_groups[mp_id] = {
|
||||||
pid = None
|
"market_place": ci.market_place,
|
||||||
groups[pid]["post_id"] = pid
|
"post_id": ci.market_place.container_id if ci.market_place else None,
|
||||||
groups[pid]["cart_items"].append(ci)
|
"cart_items": [],
|
||||||
|
"calendar_entries": [],
|
||||||
|
}
|
||||||
|
market_groups[mp_id]["cart_items"].append(ci)
|
||||||
|
|
||||||
|
# Attach calendar entries to an existing market group for the same page,
|
||||||
|
# or create a page-level group if no market group exists for that page.
|
||||||
|
page_to_market: dict[int | None, int | None] = {}
|
||||||
|
for mp_id, grp in market_groups.items():
|
||||||
|
pid = grp["post_id"]
|
||||||
|
if pid is not None and pid not in page_to_market:
|
||||||
|
page_to_market[pid] = mp_id
|
||||||
|
|
||||||
for ce in cal_entries:
|
for ce in cal_entries:
|
||||||
if ce.calendar_container_id:
|
pid = ce.calendar_container_id or None
|
||||||
pid = ce.calendar_container_id
|
if pid in page_to_market:
|
||||||
|
market_groups[page_to_market[pid]]["calendar_entries"].append(ce)
|
||||||
else:
|
else:
|
||||||
pid = None
|
# Create a page-level group for calendar-only entries
|
||||||
groups[pid]["post_id"] = pid
|
key = ("cal", pid)
|
||||||
groups[pid]["calendar_entries"].append(ce)
|
if key not in market_groups:
|
||||||
|
market_groups[key] = {
|
||||||
|
"market_place": None,
|
||||||
|
"post_id": pid,
|
||||||
|
"cart_items": [],
|
||||||
|
"calendar_entries": [],
|
||||||
|
}
|
||||||
|
if pid is not None:
|
||||||
|
page_to_market[pid] = key
|
||||||
|
market_groups[key]["calendar_entries"].append(ce)
|
||||||
|
|
||||||
# Batch-load Post DTOs and PageConfig objects
|
# Batch-load Post DTOs and PageConfig objects
|
||||||
post_ids = [pid for pid in groups if pid is not None]
|
post_ids = list({
|
||||||
|
grp["post_id"] for grp in market_groups.values()
|
||||||
|
if grp["post_id"] is not None
|
||||||
|
})
|
||||||
posts_by_id: dict[int, object] = {}
|
posts_by_id: dict[int, object] = {}
|
||||||
configs_by_post: dict[int, PageConfig] = {}
|
configs_by_post: dict[int, PageConfig] = {}
|
||||||
|
|
||||||
@@ -126,18 +147,22 @@ async def get_cart_grouped_by_page(session) -> list[dict]:
|
|||||||
for pc in pc_result.scalars().all():
|
for pc in pc_result.scalars().all():
|
||||||
configs_by_post[pc.container_id] = pc
|
configs_by_post[pc.container_id] = pc
|
||||||
|
|
||||||
# Build result list (pages first, orphan last)
|
# Build result list (markets with pages first, orphan last)
|
||||||
result = []
|
result = []
|
||||||
for pid in sorted(groups, key=lambda x: (x is None, x)):
|
for _key, grp in sorted(
|
||||||
grp = groups[pid]
|
market_groups.items(),
|
||||||
|
key=lambda kv: (kv[1]["post_id"] is None, kv[1]["post_id"] or 0),
|
||||||
|
):
|
||||||
items = grp["cart_items"]
|
items = grp["cart_items"]
|
||||||
entries = grp["calendar_entries"]
|
entries = grp["calendar_entries"]
|
||||||
prod_total = calc_product_total(items) or 0
|
prod_total = calc_product_total(items) or 0
|
||||||
cal_total = calc_calendar_total(entries) or 0
|
cal_total = calc_calendar_total(entries) or 0
|
||||||
|
pid = grp["post_id"]
|
||||||
|
|
||||||
result.append({
|
result.append({
|
||||||
"post": posts_by_id.get(pid) if pid else None,
|
"post": posts_by_id.get(pid) if pid else None,
|
||||||
"page_config": configs_by_post.get(pid) if pid else None,
|
"page_config": configs_by_post.get(pid) if pid else None,
|
||||||
|
"market_place": grp["market_place"],
|
||||||
"cart_items": items,
|
"cart_items": items,
|
||||||
"calendar_entries": entries,
|
"calendar_entries": entries,
|
||||||
"product_count": sum(ci.quantity for ci in items),
|
"product_count": sum(ci.quantity for ci in items),
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
{% if grp.cart_items or grp.calendar_entries %}
|
{% if grp.cart_items or grp.calendar_entries %}
|
||||||
|
|
||||||
{% if grp.post %}
|
{% if grp.post %}
|
||||||
{# Page cart card #}
|
{# Market / page cart card #}
|
||||||
<a
|
<a
|
||||||
href="{{ cart_url('/' + grp.post.slug + '/') }}"
|
href="{{ cart_url('/' + grp.post.slug + '/') }}"
|
||||||
class="block rounded-2xl border border-stone-200 bg-white shadow-sm hover:shadow-md hover:border-stone-300 transition p-4 sm:p-5"
|
class="block rounded-2xl border border-stone-200 bg-white shadow-sm hover:shadow-md hover:border-stone-300 transition p-4 sm:p-5"
|
||||||
@@ -53,8 +53,15 @@
|
|||||||
|
|
||||||
<div class="flex-1 min-w-0">
|
<div class="flex-1 min-w-0">
|
||||||
<h3 class="text-base sm:text-lg font-semibold text-stone-900 truncate">
|
<h3 class="text-base sm:text-lg font-semibold text-stone-900 truncate">
|
||||||
{{ grp.post.title }}
|
{% if grp.market_place %}
|
||||||
|
{{ grp.market_place.name }}
|
||||||
|
{% else %}
|
||||||
|
{{ grp.post.title }}
|
||||||
|
{% endif %}
|
||||||
</h3>
|
</h3>
|
||||||
|
{% if grp.market_place %}
|
||||||
|
<p class="text-xs text-stone-500 truncate">{{ grp.post.title }}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="mt-1 flex flex-wrap gap-2 text-xs text-stone-600">
|
<div class="mt-1 flex flex-wrap gap-2 text-xs text-stone-600">
|
||||||
{% if grp.product_count > 0 %}
|
{% if grp.product_count > 0 %}
|
||||||
|
|||||||
Reference in New Issue
Block a user