Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
Extract cart, order, and orders blueprints with their service layer, templates, Dockerfile (APP_MODULE=app:app, IMAGE=cart), entrypoint, and Gitea CI workflow from the coop monolith. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
58 lines
1.6 KiB
Python
58 lines
1.6 KiB
Python
# app/cart_merge.py
|
|
|
|
from __future__ import annotations
|
|
|
|
from quart import g, session as qsession
|
|
from sqlalchemy import select
|
|
from typing import Optional
|
|
|
|
from models.market import CartItem
|
|
|
|
|
|
async def merge_anonymous_cart_into_user(user_id: int) -> None:
|
|
"""
|
|
When a user logs in, move any anonymous cart (session_id) items onto their user_id.
|
|
"""
|
|
sid: Optional[str] = qsession.get("cart_sid")
|
|
if not sid:
|
|
return
|
|
|
|
# get all anon cart items for this session
|
|
anon_items = (
|
|
await g.s.execute(
|
|
select(CartItem).where(
|
|
CartItem.deleted_at.is_(None),
|
|
CartItem.session_id == sid,
|
|
)
|
|
)
|
|
).scalars().all()
|
|
if not anon_items:
|
|
return
|
|
|
|
# Existing user items keyed by product_id for quick merge
|
|
user_items_by_product = {
|
|
ci.product_id: ci
|
|
for ci in (
|
|
await g.s.execute(
|
|
select(CartItem).where(
|
|
CartItem.deleted_at.is_(None),
|
|
CartItem.user_id == user_id,
|
|
)
|
|
)
|
|
).scalars().all()
|
|
}
|
|
|
|
for anon in anon_items:
|
|
existing = user_items_by_product.get(anon.product_id)
|
|
if existing:
|
|
# merge quantities then soft-delete the anon row
|
|
existing.quantity += anon.quantity
|
|
anon.deleted_at = func.now()
|
|
else:
|
|
# reassign anonymous cart row to this user
|
|
anon.user_id = user_id
|
|
anon.session_id = None
|
|
|
|
# clear the anonymous session id now that it's "claimed"
|
|
qsession.pop("cart_sid", None)
|