From 5673ee125d9f852c89fe7f6add167812ae281d5c Mon Sep 17 00:00:00 2001 From: type-two Date: Tue, 23 Jun 2026 17:38:16 +1000 Subject: [PATCH] fix(sales): register GET /{sale_id} last so /settings /customers /past /discounts resolve The 1-segment parametric route was swallowing the literal GET routes (int-parse 422, silently masked before). Moved it after all literals. Co-Authored-By: Claude Opus 4.8 --- app/sales_routes.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/sales_routes.py b/app/sales_routes.py index e898702..64004e2 100644 --- a/app/sales_routes.py +++ b/app/sales_routes.py @@ -151,12 +151,6 @@ async def _load_sale(db, sale_id): return s, items, cust -@router.get("/{sale_id}") -async def sale_detail(sale_id: int, ident=Depends(require_token), db=Depends(get_db)): - s, items, cust = await _load_sale(db, sale_id) - return {"sale": s, "items": items, "customer": cust} - - @router.get("/{sale_id}/receipt") async def sale_receipt(sale_id: int, ident=Depends(require_token), db=Depends(get_db)): """Rendered receipt HTML (for the print window) + the customer's email if on file.""" @@ -335,3 +329,11 @@ async def past_sales(q: str = Query(""), ident=Depends(require_token), db=Depend {where} ORDER BY s.sale_date DESC NULLS LAST LIMIT 100 """), params) return {"sales": [dict(r) for r in rows.mappings()]} + + +# Parametric catch-all LAST so it doesn't swallow /settings, /customers, /past, /discounts +# (FastAPI matches by registration order; "/{sale_id}" regex matches any single segment). +@router.get("/{sale_id}") +async def sale_detail(sale_id: int, ident=Depends(require_token), db=Depends(get_db)): + s, items, cust = await _load_sale(db, sale_id) + return {"sale": s, "items": items, "customer": cust}