Files
orion/app/modules/catalog/routes/api/admin.py
Samir Boulahtit 6f278131a3 refactor: migrate products and vendor_products to module auto-discovery
- Move admin/products.py to marketplace module as admin_products.py
  (marketplace product catalog browsing)
- Move admin/vendor_products.py to catalog module as admin.py
  (vendor catalog management)
- Move vendor/products.py to catalog module as vendor.py
  (vendor's own product catalog)
- Update marketplace admin router to include products routes
- Update catalog module routes/api/__init__.py with lazy imports
- Remove legacy imports from admin and vendor API init files

All product routes now auto-discovered via module system.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 12:49:11 +01:00

161 lines
5.4 KiB
Python

# app/modules/catalog/routes/api/admin.py
"""
Admin vendor product catalog endpoints.
Provides management of vendor-specific product catalogs:
- Browse products in vendor catalogs
- View product details with override info
- Create/update/remove products from catalog
All routes require module access control for the 'catalog' module.
"""
import logging
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from app.api.deps import get_current_admin_api, require_module_access
from app.core.database import get_db
from app.services.subscription_service import subscription_service
from app.services.vendor_product_service import vendor_product_service
from models.schema.auth import UserContext
from app.modules.catalog.schemas import (
CatalogVendor,
CatalogVendorsResponse,
RemoveProductResponse,
VendorProductCreate,
VendorProductCreateResponse,
VendorProductDetail,
VendorProductListItem,
VendorProductListResponse,
VendorProductStats,
VendorProductUpdate,
)
admin_router = APIRouter(
prefix="/vendor-products",
dependencies=[Depends(require_module_access("catalog"))],
)
logger = logging.getLogger(__name__)
# ============================================================================
# Endpoints
# ============================================================================
@admin_router.get("", response_model=VendorProductListResponse)
def get_vendor_products(
skip: int = Query(0, ge=0),
limit: int = Query(50, ge=1, le=500),
search: str | None = Query(None, description="Search by title or SKU"),
vendor_id: int | None = Query(None, description="Filter by vendor"),
is_active: bool | None = Query(None, description="Filter by active status"),
is_featured: bool | None = Query(None, description="Filter by featured status"),
language: str = Query("en", description="Language for title lookup"),
db: Session = Depends(get_db),
current_admin: UserContext = Depends(get_current_admin_api),
):
"""
Get all products in vendor catalogs with filtering.
This endpoint allows admins to browse products that have been
copied to vendor catalogs from the marketplace repository.
"""
products, total = vendor_product_service.get_products(
db=db,
skip=skip,
limit=limit,
search=search,
vendor_id=vendor_id,
is_active=is_active,
is_featured=is_featured,
language=language,
)
return VendorProductListResponse(
products=[VendorProductListItem(**p) for p in products],
total=total,
skip=skip,
limit=limit,
)
@admin_router.get("/stats", response_model=VendorProductStats)
def get_vendor_product_stats(
vendor_id: int | None = Query(None, description="Filter stats by vendor ID"),
db: Session = Depends(get_db),
current_admin: UserContext = Depends(get_current_admin_api),
):
"""Get vendor product statistics for admin dashboard."""
stats = vendor_product_service.get_product_stats(db, vendor_id=vendor_id)
return VendorProductStats(**stats)
@admin_router.get("/vendors", response_model=CatalogVendorsResponse)
def get_catalog_vendors(
db: Session = Depends(get_db),
current_admin: UserContext = Depends(get_current_admin_api),
):
"""Get list of vendors with products in their catalogs."""
vendors = vendor_product_service.get_catalog_vendors(db)
return CatalogVendorsResponse(vendors=[CatalogVendor(**v) for v in vendors])
@admin_router.get("/{product_id}", response_model=VendorProductDetail)
def get_vendor_product_detail(
product_id: int,
db: Session = Depends(get_db),
current_admin: UserContext = Depends(get_current_admin_api),
):
"""Get detailed vendor product information including override info."""
product = vendor_product_service.get_product_detail(db, product_id)
return VendorProductDetail(**product)
@admin_router.post("", response_model=VendorProductCreateResponse)
def create_vendor_product(
data: VendorProductCreate,
db: Session = Depends(get_db),
current_admin: UserContext = Depends(get_current_admin_api),
):
"""Create a new vendor product."""
# Check product limit before creating
subscription_service.check_product_limit(db, data.vendor_id)
product = vendor_product_service.create_product(db, data.model_dump())
db.commit()
return VendorProductCreateResponse(
id=product.id, message="Product created successfully"
)
@admin_router.patch("/{product_id}", response_model=VendorProductDetail)
def update_vendor_product(
product_id: int,
data: VendorProductUpdate,
db: Session = Depends(get_db),
current_admin: UserContext = Depends(get_current_admin_api),
):
"""Update a vendor product."""
# Only include fields that were explicitly set
update_data = data.model_dump(exclude_unset=True)
vendor_product_service.update_product(db, product_id, update_data)
db.commit()
# Return the updated product detail
product = vendor_product_service.get_product_detail(db, product_id)
return VendorProductDetail(**product)
@admin_router.delete("/{product_id}", response_model=RemoveProductResponse)
def remove_vendor_product(
product_id: int,
db: Session = Depends(get_db),
current_admin: UserContext = Depends(get_current_admin_api),
):
"""Remove a product from vendor catalog."""
result = vendor_product_service.remove_product(db, product_id)
db.commit()
return RemoveProductResponse(**result)