feat: initialize cart app with blueprints, templates, and CI
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>
This commit is contained in:
giles
2026-02-09 23:17:41 +00:00
commit 967303093d
46 changed files with 2472 additions and 0 deletions

80
app.py Normal file
View File

@@ -0,0 +1,80 @@
from __future__ import annotations
from quart import g
from shared.factory import create_base_app
from suma_browser.app.bp import register_cart_bp, register_orders, register_cart_api
from suma_browser.app.bp.cart.services import (
get_cart,
total,
get_calendar_cart_entries,
calendar_total,
)
async def _load_cart():
"""Load the full cart for the cart app (before each request)."""
g.cart = await get_cart(g.s)
async def cart_context() -> dict:
"""
Cart app context processor.
- cart / calendar_cart_entries / total / calendar_total: direct DB
(cart app owns this data)
- cart_count: derived from cart + calendar entries (for _mini.html)
- menu_items: fetched from coop internal API
"""
from shared.context import base_context
from shared.internal_api import get as api_get, dictobj
ctx = await base_context()
# Cart app owns cart data — use g.cart from _load_cart
cart = getattr(g, "cart", None) or []
cal_entries = await get_calendar_cart_entries(g.s)
ctx["cart"] = cart
ctx["calendar_cart_entries"] = cal_entries
ctx["total"] = total
ctx["calendar_total"] = calendar_total
# Also set cart_count so _mini.html works the same way
cart_qty = sum(ci.quantity for ci in cart) if cart else 0
ctx["cart_count"] = cart_qty + len(cal_entries)
ctx["cart_total"] = (total(cart) or 0) + (calendar_total(cal_entries) or 0)
# Menu items from coop API (wrapped for attribute access in templates)
menu_data = await api_get("coop", "/internal/menu-items")
ctx["menu_items"] = dictobj(menu_data) if menu_data else []
return ctx
def create_app() -> "Quart":
app = create_base_app(
"cart",
context_fn=cart_context,
before_request_fns=[_load_cart],
)
# Cart blueprint at root (was /cart in monolith)
app.register_blueprint(
register_cart_bp(url_prefix="/"),
url_prefix="/",
)
# Orders blueprint
app.register_blueprint(
register_orders(url_prefix="/orders"),
)
# Internal API (server-to-server, CSRF-exempt)
app.register_blueprint(register_cart_api())
return app
app = create_app()