From 8527ddb84b68e83e778a17c0a8f52a206e01826e Mon Sep 17 00:00:00 2001 From: giles Date: Wed, 18 Feb 2026 20:58:10 +0000 Subject: [PATCH] Decouple cart: use shared.models for all cross-app imports - Replace all imports from blog.models, market.models, events.models and bare models.* with shared.models equivalents - Convert cart/models/order.py and page_config.py to re-export stubs - Update shared + glue submodule pointers Co-Authored-By: Claude Opus 4.6 --- app.py | 4 +- bp/cart/api.py | 8 +- bp/cart/global_routes.py | 6 +- bp/cart/services/calendar_cart.py | 2 +- bp/cart/services/checkout.py | 10 +- bp/cart/services/clear_cart_for_order.py | 6 +- bp/cart/services/get_cart.py | 2 +- bp/cart/services/page_cart.py | 10 +- bp/order/routes.py | 4 +- bp/orders/routes.py | 4 +- glue | 2 +- models/order.py | 115 +---------------------- models/page_config.py | 40 +------- shared | 2 +- 14 files changed, 32 insertions(+), 183 deletions(-) diff --git a/app.py b/app.py index e6abe30..19cbd8a 100644 --- a/app.py +++ b/app.py @@ -81,8 +81,8 @@ async def cart_context() -> dict: def create_app() -> "Quart": - from blog.models.ghost_content import Post - from models.page_config import PageConfig + from shared.models.ghost_content import Post + from shared.models.page_config import PageConfig app = create_base_app( "cart", diff --git a/bp/cart/api.py b/bp/cart/api.py index 6eab95d..15bfe5b 100644 --- a/bp/cart/api.py +++ b/bp/cart/api.py @@ -10,10 +10,10 @@ from quart import Blueprint, g, request, jsonify from sqlalchemy import select from sqlalchemy.orm import selectinload -from market.models.market import CartItem -from market.models.market_place import MarketPlace -from events.models.calendars import CalendarEntry, Calendar -from blog.models.ghost_content import Post +from shared.models.market import CartItem +from shared.models.market_place import MarketPlace +from shared.models.calendars import CalendarEntry, Calendar +from shared.models.ghost_content import Post from shared.browser.app.csrf import csrf_exempt from shared.infrastructure.cart_identity import current_cart_identity diff --git a/bp/cart/global_routes.py b/bp/cart/global_routes.py index 83bd8d1..47481e8 100644 --- a/bp/cart/global_routes.py +++ b/bp/cart/global_routes.py @@ -5,9 +5,9 @@ from __future__ import annotations from quart import Blueprint, g, request, render_template, redirect, url_for, make_response from sqlalchemy import select -from models.order import Order -from blog.models.ghost_content import Post -from market.models.market_place import MarketPlace +from shared.models.order import Order +from shared.models.ghost_content import Post +from shared.models.market_place import MarketPlace from glue.services.order_lifecycle import get_entries_for_order from .services import ( current_cart_identity, diff --git a/bp/cart/services/calendar_cart.py b/bp/cart/services/calendar_cart.py index f985ff4..434cbbd 100644 --- a/bp/cart/services/calendar_cart.py +++ b/bp/cart/services/calendar_cart.py @@ -3,7 +3,7 @@ from __future__ import annotations from sqlalchemy import select from sqlalchemy.orm import selectinload -from events.models.calendars import CalendarEntry +from shared.models.calendars import CalendarEntry from .identity import current_cart_identity diff --git a/bp/cart/services/checkout.py b/bp/cart/services/checkout.py index 0c955e3..3d83884 100644 --- a/bp/cart/services/checkout.py +++ b/bp/cart/services/checkout.py @@ -7,11 +7,11 @@ from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload -from market.models.market import Product, CartItem -from models.order import Order, OrderItem -from events.models.calendars import CalendarEntry, Calendar -from models.page_config import PageConfig -from market.models.market_place import MarketPlace +from shared.models.market import Product, CartItem +from shared.models.order import Order, OrderItem +from shared.models.calendars import CalendarEntry, Calendar +from shared.models.page_config import PageConfig +from shared.models.market_place import MarketPlace from shared.config import config from shared.events import emit_event from glue.services.order_lifecycle import claim_entries_for_order diff --git a/bp/cart/services/clear_cart_for_order.py b/bp/cart/services/clear_cart_for_order.py index 822d71d..3643839 100644 --- a/bp/cart/services/clear_cart_for_order.py +++ b/bp/cart/services/clear_cart_for_order.py @@ -1,8 +1,8 @@ from sqlalchemy import update, func, select -from market.models.market import CartItem -from market.models.market_place import MarketPlace -from models.order import Order +from shared.models.market import CartItem +from shared.models.market_place import MarketPlace +from shared.models.order import Order async def clear_cart_for_order(session, order: Order, *, page_post_id: int | None = None) -> None: diff --git a/bp/cart/services/get_cart.py b/bp/cart/services/get_cart.py index 1f0886b..ad1c0ce 100644 --- a/bp/cart/services/get_cart.py +++ b/bp/cart/services/get_cart.py @@ -1,7 +1,7 @@ from sqlalchemy import select from sqlalchemy.orm import selectinload -from market.models.market import CartItem +from shared.models.market import CartItem from .identity import current_cart_identity async def get_cart(session): diff --git a/bp/cart/services/page_cart.py b/bp/cart/services/page_cart.py index eb83bf6..454865c 100644 --- a/bp/cart/services/page_cart.py +++ b/bp/cart/services/page_cart.py @@ -12,11 +12,11 @@ from collections import defaultdict from sqlalchemy import select from sqlalchemy.orm import selectinload -from market.models.market import CartItem -from market.models.market_place import MarketPlace -from events.models.calendars import CalendarEntry, Calendar -from blog.models.ghost_content import Post -from models.page_config import PageConfig +from shared.models.market import CartItem +from shared.models.market_place import MarketPlace +from shared.models.calendars import CalendarEntry, Calendar +from shared.models.ghost_content import Post +from shared.models.page_config import PageConfig from .identity import current_cart_identity diff --git a/bp/order/routes.py b/bp/order/routes.py index 75a35eb..b85087f 100644 --- a/bp/order/routes.py +++ b/bp/order/routes.py @@ -5,8 +5,8 @@ from sqlalchemy import select, func, or_, cast, String, exists from sqlalchemy.orm import selectinload -from market.models.market import Product -from models.order import Order, OrderItem +from shared.models.market import Product +from shared.models.order import Order, OrderItem from shared.browser.app.payments.sumup import create_checkout as sumup_create_checkout from shared.config import config diff --git a/bp/orders/routes.py b/bp/orders/routes.py index de8cc35..e7363c2 100644 --- a/bp/orders/routes.py +++ b/bp/orders/routes.py @@ -5,8 +5,8 @@ from sqlalchemy import select, func, or_, cast, String, exists from sqlalchemy.orm import selectinload -from market.models.market import Product -from models.order import Order, OrderItem +from shared.models.market import Product +from shared.models.order import Order, OrderItem from shared.browser.app.payments.sumup import create_checkout as sumup_create_checkout from shared.config import config diff --git a/glue b/glue index fc14d83..ebce44e 160000 --- a/glue +++ b/glue @@ -1 +1 @@ -Subproject commit fc14d8323adcb404894c8ab875431c9d571cfabb +Subproject commit ebce44e9d9ae0938647290a1e98687ae79fd71eb diff --git a/models/order.py b/models/order.py index 4f2f547..93953fe 100644 --- a/models/order.py +++ b/models/order.py @@ -1,114 +1 @@ -from __future__ import annotations - -from datetime import datetime -from typing import Optional, List - -from sqlalchemy import Integer, String, DateTime, ForeignKey, Numeric, func, Text -from sqlalchemy.orm import Mapped, mapped_column, relationship - -from shared.db.base import Base - - -class Order(Base): - __tablename__ = "orders" - - id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) - - user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("users.id"), nullable=True) - session_id: Mapped[Optional[str]] = mapped_column(String(64), index=True, nullable=True) - - page_config_id: Mapped[Optional[int]] = mapped_column( - ForeignKey("page_configs.id", ondelete="SET NULL"), - nullable=True, - index=True, - ) - - status: Mapped[str] = mapped_column( - String(32), - nullable=False, - default="pending", - server_default="pending", - ) - currency: Mapped[str] = mapped_column(String(16), nullable=False, default="GBP") - total_amount: Mapped[float] = mapped_column(Numeric(12, 2), nullable=False) - - # free-form description for the order - description: Mapped[Optional[str]] = mapped_column(Text, nullable=True, index=True) - - # SumUp reference string (what we send as checkout_reference) - sumup_reference: Mapped[Optional[str]] = mapped_column( - String(255), - nullable=True, - index=True, - ) - - # SumUp integration fields - sumup_checkout_id: Mapped[Optional[str]] = mapped_column( - String(128), - nullable=True, - index=True, - ) - sumup_status: Mapped[Optional[str]] = mapped_column(String(32), nullable=True) - sumup_hosted_url: Mapped[Optional[str]] = mapped_column(Text, nullable=True) - - created_at: Mapped[datetime] = mapped_column( - DateTime(timezone=True), - nullable=False, - server_default=func.now(), - ) - updated_at: Mapped[datetime] = mapped_column( - DateTime(timezone=True), - nullable=False, - server_default=func.now(), - onupdate=func.now(), - ) - - items: Mapped[List["OrderItem"]] = relationship( - "OrderItem", - back_populates="order", - cascade="all, delete-orphan", - lazy="selectin", - ) - page_config: Mapped[Optional["PageConfig"]] = relationship( - "PageConfig", - foreign_keys=[page_config_id], - lazy="selectin", - ) - - -class OrderItem(Base): - __tablename__ = "order_items" - - id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) - order_id: Mapped[int] = mapped_column( - ForeignKey("orders.id", ondelete="CASCADE"), - nullable=False, - ) - - product_id: Mapped[int] = mapped_column( - ForeignKey("products.id"), - nullable=False, - ) - product_title: Mapped[Optional[str]] = mapped_column(String(512), nullable=True) - - quantity: Mapped[int] = mapped_column(Integer, nullable=False, default=1) - unit_price: Mapped[float] = mapped_column(Numeric(12, 2), nullable=False) - currency: Mapped[str] = mapped_column(String(16), nullable=False, default="GBP") - - created_at: Mapped[datetime] = mapped_column( - DateTime(timezone=True), - nullable=False, - server_default=func.now(), - ) - - order: Mapped["Order"] = relationship( - "Order", - back_populates="items", - ) - - # NEW: link each order item to its product - product: Mapped["Product"] = relationship( - "Product", - back_populates="order_items", - lazy="selectin", - ) +from shared.models.order import Order, OrderItem # noqa: F401 diff --git a/models/page_config.py b/models/page_config.py index adb6561..ec23c6d 100644 --- a/models/page_config.py +++ b/models/page_config.py @@ -1,39 +1 @@ -from __future__ import annotations - -from datetime import datetime -from typing import Optional - -from sqlalchemy import Integer, String, Text, DateTime, func, JSON, text -from sqlalchemy.orm import Mapped, mapped_column, relationship - -from shared.db.base import Base - - -class PageConfig(Base): - __tablename__ = "page_configs" - - id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) - - container_type: Mapped[str] = mapped_column( - String(32), nullable=False, server_default=text("'page'"), - ) - container_id: Mapped[int] = mapped_column(Integer, nullable=False) - - features: Mapped[dict] = mapped_column( - JSON, nullable=False, server_default="{}" - ) - - # Per-page SumUp credentials (NULL until configured) - sumup_merchant_code: Mapped[Optional[str]] = mapped_column(String(64), nullable=True) - sumup_api_key: Mapped[Optional[str]] = mapped_column(Text(), nullable=True) - sumup_checkout_prefix: Mapped[Optional[str]] = mapped_column(String(64), nullable=True) - - created_at: Mapped[datetime] = mapped_column( - DateTime(timezone=True), nullable=False, server_default=func.now() - ) - updated_at: Mapped[datetime] = mapped_column( - DateTime(timezone=True), nullable=False, server_default=func.now() - ) - deleted_at: Mapped[Optional[datetime]] = mapped_column( - DateTime(timezone=True), nullable=True - ) +from shared.models.page_config import PageConfig # noqa: F401 diff --git a/shared b/shared index da10fc4..0c0f3c8 160000 --- a/shared +++ b/shared @@ -1 +1 @@ -Subproject commit da10fc4cf91d355342decb2c47e4d4e279e981a1 +Subproject commit 0c0f3c84167ff61ad469e1f5ad93de7841c59e76