Split cart into 4 microservices: relations, likes, orders, page-config→blog
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
Phase 1 - Relations service (internal): owns ContainerRelation, exposes get-children data + attach/detach-child actions. Retargeted events, blog, market callers from cart to relations. Phase 2 - Likes service (internal): unified Like model replaces ProductLike and PostLike with generic target_type/target_slug/target_id. Exposes is-liked, liked-slugs, liked-ids data + toggle action. Phase 3 - PageConfig → blog: moved ownership to blog with direct DB queries, removed proxy endpoints from cart. Phase 4 - Orders service (public): owns Order/OrderItem + SumUp checkout flow. Cart checkout now delegates to orders via create-order action. Webhook/return routes and reconciliation moved to orders. Phase 5 - Infrastructure: docker-compose, deploy.sh, Dockerfiles updated for all 3 new services. Added orders_url helper and factory model imports. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
66
cart/app.py
66
cart/app.py
@@ -15,7 +15,6 @@ from bp import (
|
||||
register_cart_overview,
|
||||
register_page_cart,
|
||||
register_cart_global,
|
||||
register_orders,
|
||||
register_fragments,
|
||||
register_actions,
|
||||
register_data,
|
||||
@@ -121,7 +120,6 @@ def _make_page_config(raw: dict) -> SimpleNamespace:
|
||||
|
||||
|
||||
def create_app() -> "Quart":
|
||||
from shared.services.registry import services
|
||||
from services import register_domain_services
|
||||
|
||||
app = create_base_app(
|
||||
@@ -184,10 +182,7 @@ def create_app() -> "Quart":
|
||||
# --- Blueprint registration ---
|
||||
# Static prefixes first, dynamic (page_slug) last
|
||||
|
||||
# Orders blueprint
|
||||
app.register_blueprint(register_orders(url_prefix="/orders"))
|
||||
|
||||
# Global routes (webhook, return, add — specific paths under /)
|
||||
# Global routes (add, quantity, delete, checkout — specific paths under /)
|
||||
app.register_blueprint(
|
||||
register_cart_global(url_prefix="/"),
|
||||
url_prefix="/",
|
||||
@@ -205,65 +200,6 @@ def create_app() -> "Quart":
|
||||
url_prefix="/<page_slug>",
|
||||
)
|
||||
|
||||
# --- Reconcile stale pending orders on startup ---
|
||||
@app.before_serving
|
||||
async def _reconcile_pending_orders():
|
||||
"""Check SumUp status for orders stuck in 'pending' with a checkout ID.
|
||||
|
||||
Handles the case where SumUp webhooks fired while the service was down
|
||||
or were rejected (e.g. CSRF). Runs once on boot.
|
||||
"""
|
||||
import logging
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from sqlalchemy import select as sel
|
||||
from shared.db.session import get_session
|
||||
from shared.models.order import Order
|
||||
from shared.infrastructure.data_client import fetch_data
|
||||
from bp.cart.services.check_sumup_status import check_sumup_status
|
||||
|
||||
log = logging.getLogger("cart.reconcile")
|
||||
|
||||
try:
|
||||
async with get_session() as sess:
|
||||
async with sess.begin():
|
||||
cutoff = datetime.now(timezone.utc) - timedelta(minutes=2)
|
||||
result = await sess.execute(
|
||||
sel(Order)
|
||||
.where(
|
||||
Order.status == "pending",
|
||||
Order.sumup_checkout_id.isnot(None),
|
||||
Order.created_at < cutoff,
|
||||
)
|
||||
.limit(50)
|
||||
)
|
||||
stale_orders = result.scalars().all()
|
||||
|
||||
if not stale_orders:
|
||||
return
|
||||
|
||||
log.info("Reconciling %d stale pending orders", len(stale_orders))
|
||||
for order in stale_orders:
|
||||
try:
|
||||
# Fetch page_config from blog if order has one
|
||||
pc = None
|
||||
if order.page_config_id:
|
||||
raw_pc = await fetch_data(
|
||||
"blog", "page-config-by-id",
|
||||
params={"id": order.page_config_id},
|
||||
required=False,
|
||||
)
|
||||
if raw_pc:
|
||||
pc = _make_page_config(raw_pc)
|
||||
await check_sumup_status(sess, order, page_config=pc)
|
||||
log.info(
|
||||
"Order %d reconciled: %s",
|
||||
order.id, order.status,
|
||||
)
|
||||
except Exception:
|
||||
log.exception("Failed to reconcile order %d", order.id)
|
||||
except Exception:
|
||||
log.exception("Order reconciliation failed")
|
||||
|
||||
return app
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user