This repository has been archived on 2026-02-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
cart/bp/orders/routes.py
giles 5d0653bf2e feat: decouple cart from shared_lib, add app-owned models
Phase 1-3 of decoupling:
- path_setup.py adds project root to sys.path
- Cart-owned models in cart/models/ (order, page_config)
- All imports updated: shared.infrastructure, shared.db, shared.browser, etc.
- PageConfig uses container_type/container_id instead of post_id FK

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 12:46:34 +00:00

140 lines
4.8 KiB
Python

from __future__ import annotations
from quart import Blueprint, g, render_template, redirect, url_for, make_response
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.browser.app.payments.sumup import create_checkout as sumup_create_checkout
from shared.config import config
from shared.infrastructure.http_utils import vary as _vary, current_url_without_page as _current_url_without_page
from bp.cart.services import check_sumup_status
from shared.browser.app.utils.htmx import is_htmx_request
from bp import register_order
from .filters.qs import makeqs_factory, decode
def register(url_prefix: str) -> Blueprint:
bp = Blueprint("orders", __name__, url_prefix=url_prefix)
bp.register_blueprint(
register_order(),
)
ORDERS_PER_PAGE = 10 # keep in sync with browse page size / your preference
@bp.before_request
def route():
# this is the crucial bit for the |qs filter
g.makeqs_factory = makeqs_factory
@bp.get("/")
async def list_orders():
# --- decode filters from query string (page + search) ---
q = decode()
page, search = q.page, q.search
# sanity clamp page
if page < 1:
page = 1
# --- build where clause for search ---
where_clause = None
if search:
term = f"%{search.strip()}%"
conditions = [
Order.status.ilike(term),
Order.currency.ilike(term),
Order.sumup_checkout_id.ilike(term),
Order.sumup_status.ilike(term),
Order.description.ilike(term),
]
conditions.append(
exists(
select(1)
.select_from(OrderItem)
.join(Product, Product.id == OrderItem.product_id)
.where(
OrderItem.order_id == Order.id,
or_(
OrderItem.product_title.ilike(term),
Product.title.ilike(term),
Product.description_short.ilike(term),
Product.description_html.ilike(term),
Product.slug.ilike(term),
Product.brand.ilike(term),
),
)
)
)
# allow exact ID match or partial (string) match
try:
search_id = int(search)
except (TypeError, ValueError):
search_id = None
if search_id is not None:
conditions.append(Order.id == search_id)
else:
conditions.append(cast(Order.id, String).ilike(term))
where_clause = or_(*conditions)
# --- total count & total pages (respecting search) ---
count_stmt = select(func.count()).select_from(Order)
if where_clause is not None:
count_stmt = count_stmt.where(where_clause)
total_count_result = await g.s.execute(count_stmt)
total_count = total_count_result.scalar_one() or 0
total_pages = max(1, (total_count + ORDERS_PER_PAGE - 1) // ORDERS_PER_PAGE)
# clamp page if beyond range (just in case)
if page > total_pages:
page = total_pages
# --- paginated orders (respecting search) ---
offset = (page - 1) * ORDERS_PER_PAGE
stmt = (
select(Order)
.order_by(Order.created_at.desc())
.offset(offset)
.limit(ORDERS_PER_PAGE)
)
if where_clause is not None:
stmt = stmt.where(where_clause)
result = await g.s.execute(stmt)
orders = result.scalars().all()
context = {
"orders": orders,
"page": page,
"total_pages": total_pages,
"search": search,
"search_count": total_count, # For search display
}
# Determine which template to use based on request type and pagination
if not is_htmx_request():
# Normal browser request: full page with layout
html = await render_template("_types/orders/index.html", **context)
elif page > 1:
# HTMX pagination: just table rows + sentinel
html = await render_template("_types/orders/_rows.html", **context)
else:
# HTMX navigation (page 1): main panel + OOB elements
html = await render_template("_types/orders/_oob_elements.html", **context)
resp = await make_response(html)
resp.headers["Hx-Push-Url"] = _current_url_without_page()
return _vary(resp)
return bp