From 44de82eb47d2184235ae8b8335fc560a60776e19 Mon Sep 17 00:00:00 2001 From: Samir Boulahtit Date: Thu, 25 Dec 2025 22:49:59 +0100 Subject: [PATCH] fix: reorder subscription routes to prevent /stats matching /{vendor_id} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FastAPI was matching /stats as a vendor_id (expecting int), causing 422 error. Move /stats and /billing/history endpoints BEFORE /{vendor_id} so they take precedence. Route order now: 1. /tiers/* - tier management 2. / - list subscriptions 3. /stats - statistics (before /{vendor_id}) 4. /billing/history - billing history (before /{vendor_id}) 5. /{vendor_id} - vendor detail endpoints (catch-all for ints) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- app/api/v1/admin/subscriptions.py | 107 ++++++++++++++++-------------- 1 file changed, 56 insertions(+), 51 deletions(-) diff --git a/app/api/v1/admin/subscriptions.py b/app/api/v1/admin/subscriptions.py index a61a7bb4..6eda8718 100644 --- a/app/api/v1/admin/subscriptions.py +++ b/app/api/v1/admin/subscriptions.py @@ -159,54 +159,19 @@ def list_vendor_subscriptions( ) -@router.get("/{vendor_id}", response_model=VendorSubscriptionWithVendor) -def get_vendor_subscription( - vendor_id: int = Path(..., description="Vendor ID"), +# ============================================================================ +# Statistics Endpoints +# ============================================================================ + + +@router.get("/stats", response_model=SubscriptionStatsResponse) +def get_subscription_stats( current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): - """Get subscription details for a specific vendor.""" - sub, vendor = admin_subscription_service.get_subscription(db, vendor_id) - - return VendorSubscriptionWithVendor( - **VendorSubscriptionResponse.model_validate(sub).model_dump(), - vendor_name=vendor.name, - vendor_code=vendor.subdomain, - orders_limit=sub.orders_limit, - products_limit=sub.products_limit, - team_members_limit=sub.team_members_limit, - ) - - -@router.patch("/{vendor_id}", response_model=VendorSubscriptionWithVendor) -def update_vendor_subscription( - update_data: VendorSubscriptionUpdate, - vendor_id: int = Path(..., description="Vendor ID"), - current_user: User = Depends(get_current_admin_api), - db: Session = Depends(get_db), -): - """ - Update a vendor's subscription. - - Allows admins to: - - Change tier - - Update status - - Set custom limit overrides - - Extend trial period - """ - data = update_data.model_dump(exclude_unset=True) - sub, vendor = admin_subscription_service.update_subscription(db, vendor_id, data) - db.commit() - db.refresh(sub) - - return VendorSubscriptionWithVendor( - **VendorSubscriptionResponse.model_validate(sub).model_dump(), - vendor_name=vendor.name, - vendor_code=vendor.subdomain, - orders_limit=sub.orders_limit, - products_limit=sub.products_limit, - team_members_limit=sub.team_members_limit, - ) + """Get subscription statistics for admin dashboard.""" + stats = admin_subscription_service.get_stats(db) + return SubscriptionStatsResponse(**stats) # ============================================================================ @@ -262,15 +227,55 @@ def list_billing_history( # ============================================================================ -# Statistics Endpoints +# Vendor Subscription Detail Endpoints # ============================================================================ -@router.get("/stats", response_model=SubscriptionStatsResponse) -def get_subscription_stats( +@router.get("/{vendor_id}", response_model=VendorSubscriptionWithVendor) +def get_vendor_subscription( + vendor_id: int = Path(..., description="Vendor ID"), current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): - """Get subscription statistics for admin dashboard.""" - stats = admin_subscription_service.get_stats(db) - return SubscriptionStatsResponse(**stats) + """Get subscription details for a specific vendor.""" + sub, vendor = admin_subscription_service.get_subscription(db, vendor_id) + + return VendorSubscriptionWithVendor( + **VendorSubscriptionResponse.model_validate(sub).model_dump(), + vendor_name=vendor.name, + vendor_code=vendor.subdomain, + orders_limit=sub.orders_limit, + products_limit=sub.products_limit, + team_members_limit=sub.team_members_limit, + ) + + +@router.patch("/{vendor_id}", response_model=VendorSubscriptionWithVendor) +def update_vendor_subscription( + update_data: VendorSubscriptionUpdate, + vendor_id: int = Path(..., description="Vendor ID"), + current_user: User = Depends(get_current_admin_api), + db: Session = Depends(get_db), +): + """ + Update a vendor's subscription. + + Allows admins to: + - Change tier + - Update status + - Set custom limit overrides + - Extend trial period + """ + data = update_data.model_dump(exclude_unset=True) + sub, vendor = admin_subscription_service.update_subscription(db, vendor_id, data) + db.commit() + db.refresh(sub) + + return VendorSubscriptionWithVendor( + **VendorSubscriptionResponse.model_validate(sub).model_dump(), + vendor_name=vendor.name, + vendor_code=vendor.subdomain, + orders_limit=sub.orders_limit, + products_limit=sub.products_limit, + team_members_limit=sub.team_members_limit, + )