code quality run

This commit is contained in:
2025-09-13 21:58:54 +02:00
parent 0dfd885847
commit 3eb18ef91e
63 changed files with 1802 additions and 1289 deletions

View File

@@ -1,10 +1,11 @@
from fastapi import Depends, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from sqlalchemy.orm import Session
from app.core.database import get_db
from models.database_models import User, Shop
from middleware.auth import AuthManager
from middleware.rate_limiter import RateLimiter
from models.database_models import Shop, User
# Set auto_error=False to prevent automatic 403 responses
security = HTTPBearer(auto_error=False)
@@ -13,8 +14,8 @@ rate_limiter = RateLimiter()
def get_current_user(
credentials: HTTPAuthorizationCredentials = Depends(security),
db: Session = Depends(get_db)
credentials: HTTPAuthorizationCredentials = Depends(security),
db: Session = Depends(get_db),
):
"""Get current authenticated user"""
# Check if credentials are provided
@@ -30,9 +31,9 @@ def get_current_admin_user(current_user: User = Depends(get_current_user)):
def get_user_shop(
shop_code: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
shop_code: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""Get shop and verify user ownership"""
shop = db.query(Shop).filter(Shop.shop_code == shop_code.upper()).first()

View File

@@ -1,5 +1,6 @@
from fastapi import APIRouter
from app.api.v1 import auth, product, stock, shop, marketplace, admin, stats
from app.api.v1 import admin, auth, marketplace, product, shop, stats, stock
api_router = APIRouter()
@@ -9,6 +10,5 @@ api_router.include_router(auth.router, tags=["authentication"])
api_router.include_router(marketplace.router, tags=["marketplace"])
api_router.include_router(product.router, tags=["product"])
api_router.include_router(shop.router, tags=["shop"])
api_router.include_router(stats.router, tags=["statistics"])
api_router.include_router(stats.router, tags=["statistics"])
api_router.include_router(stock.router, tags=["stock"])

View File

@@ -1,13 +1,15 @@
import logging
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.api.deps import get_current_admin_user
from app.core.database import get_db
from app.services.admin_service import admin_service
from models.api_models import MarketplaceImportJobResponse, UserResponse, ShopListResponse
from models.api_models import (MarketplaceImportJobResponse, ShopListResponse,
UserResponse)
from models.database_models import User
import logging
router = APIRouter()
logger = logging.getLogger(__name__)
@@ -16,10 +18,10 @@ logger = logging.getLogger(__name__)
# Admin-only routes
@router.get("/admin/users", response_model=List[UserResponse])
def get_all_users(
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user)
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user),
):
"""Get all users (Admin only)"""
try:
@@ -32,9 +34,9 @@ def get_all_users(
@router.put("/admin/users/{user_id}/status")
def toggle_user_status(
user_id: int,
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user)
user_id: int,
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user),
):
"""Toggle user active status (Admin only)"""
try:
@@ -49,21 +51,16 @@ def toggle_user_status(
@router.get("/admin/shops", response_model=ShopListResponse)
def get_all_shops_admin(
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user)
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user),
):
"""Get all shops with admin view (Admin only)"""
try:
shops, total = admin_service.get_all_shops(db=db, skip=skip, limit=limit)
return ShopListResponse(
shops=shops,
total=total,
skip=skip,
limit=limit
)
return ShopListResponse(shops=shops, total=total, skip=skip, limit=limit)
except Exception as e:
logger.error(f"Error getting shops: {str(e)}")
raise HTTPException(status_code=500, detail="Internal server error")
@@ -71,9 +68,9 @@ def get_all_shops_admin(
@router.put("/admin/shops/{shop_id}/verify")
def verify_shop(
shop_id: int,
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user)
shop_id: int,
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user),
):
"""Verify/unverify shop (Admin only)"""
try:
@@ -88,9 +85,9 @@ def verify_shop(
@router.put("/admin/shops/{shop_id}/status")
def toggle_shop_status(
shop_id: int,
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user)
shop_id: int,
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user),
):
"""Toggle shop active status (Admin only)"""
try:
@@ -103,15 +100,17 @@ def toggle_shop_status(
raise HTTPException(status_code=500, detail="Internal server error")
@router.get("/admin/marketplace-import-jobs", response_model=List[MarketplaceImportJobResponse])
@router.get(
"/admin/marketplace-import-jobs", response_model=List[MarketplaceImportJobResponse]
)
def get_all_marketplace_import_jobs(
marketplace: Optional[str] = Query(None),
shop_name: Optional[str] = Query(None),
status: Optional[str] = Query(None),
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=100),
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user)
marketplace: Optional[str] = Query(None),
shop_name: Optional[str] = Query(None),
status: Optional[str] = Query(None),
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=100),
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user),
):
"""Get all marketplace import jobs (Admin only)"""
try:
@@ -121,7 +120,7 @@ def get_all_marketplace_import_jobs(
shop_name=shop_name,
status=status,
skip=skip,
limit=limit
limit=limit,
)
except Exception as e:
logger.error(f"Error getting marketplace import jobs: {str(e)}")

View File

@@ -1,11 +1,14 @@
import logging
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.api.deps import get_current_user
from app.core.database import get_db
from app.services.auth_service import auth_service
from models.api_models import UserRegister, UserLogin, UserResponse, LoginResponse
from models.api_models import (LoginResponse, UserLogin, UserRegister,
UserResponse)
from models.database_models import User
import logging
router = APIRouter()
logger = logging.getLogger(__name__)
@@ -35,7 +38,7 @@ def login_user(user_credentials: UserLogin, db: Session = Depends(get_db)):
access_token=login_result["token_data"]["access_token"],
token_type=login_result["token_data"]["token_type"],
expires_in=login_result["token_data"]["expires_in"],
user=UserResponse.model_validate(login_result["user"])
user=UserResponse.model_validate(login_result["user"]),
)
except HTTPException:
raise

View File

@@ -1,15 +1,17 @@
import logging
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query, BackgroundTasks
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.api.deps import get_current_user
from app.core.database import get_db
from app.services.marketplace_service import marketplace_service
from app.tasks.background_tasks import process_marketplace_import
from middleware.decorators import rate_limit
from models.api_models import MarketplaceImportJobResponse, MarketplaceImportRequest
from models.api_models import (MarketplaceImportJobResponse,
MarketplaceImportRequest)
from models.database_models import User
from app.services.marketplace_service import marketplace_service
import logging
router = APIRouter()
logger = logging.getLogger(__name__)
@@ -19,15 +21,16 @@ logger = logging.getLogger(__name__)
@router.post("/marketplace/import-product", response_model=MarketplaceImportJobResponse)
@rate_limit(max_requests=10, window_seconds=3600) # Limit marketplace imports
async def import_products_from_marketplace(
request: MarketplaceImportRequest,
background_tasks: BackgroundTasks,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
request: MarketplaceImportRequest,
background_tasks: BackgroundTasks,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Import products from marketplace CSV with background processing (Protected)"""
try:
logger.info(
f"Starting marketplace import: {request.marketplace} -> {request.shop_code} by user {current_user.username}")
f"Starting marketplace import: {request.marketplace} -> {request.shop_code} by user {current_user.username}"
)
# Create import job through service
import_job = marketplace_service.create_import_job(db, request, current_user)
@@ -39,7 +42,7 @@ async def import_products_from_marketplace(
request.url,
request.marketplace,
request.shop_code,
request.batch_size or 1000
request.batch_size or 1000,
)
return MarketplaceImportJobResponse(
@@ -50,7 +53,7 @@ async def import_products_from_marketplace(
shop_id=import_job.shop_id,
shop_name=import_job.shop_name,
message=f"Marketplace import started from {request.marketplace}. Check status with "
f"/import-status/{import_job.id}"
f"/import-status/{import_job.id}",
)
except ValueError as e:
@@ -62,11 +65,13 @@ async def import_products_from_marketplace(
raise HTTPException(status_code=500, detail="Internal server error")
@router.get("/marketplace/import-status/{job_id}", response_model=MarketplaceImportJobResponse)
@router.get(
"/marketplace/import-status/{job_id}", response_model=MarketplaceImportJobResponse
)
def get_marketplace_import_status(
job_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
job_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get status of marketplace import job (Protected)"""
try:
@@ -82,14 +87,16 @@ def get_marketplace_import_status(
raise HTTPException(status_code=500, detail="Internal server error")
@router.get("/marketplace/import-jobs", response_model=List[MarketplaceImportJobResponse])
@router.get(
"/marketplace/import-jobs", response_model=List[MarketplaceImportJobResponse]
)
def get_marketplace_import_jobs(
marketplace: Optional[str] = Query(None, description="Filter by marketplace"),
shop_name: Optional[str] = Query(None, description="Filter by shop name"),
skip: int = Query(0, ge=0),
limit: int = Query(50, ge=1, le=100),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
marketplace: Optional[str] = Query(None, description="Filter by marketplace"),
shop_name: Optional[str] = Query(None, description="Filter by shop name"),
skip: int = Query(0, ge=0),
limit: int = Query(50, ge=1, le=100),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get marketplace import jobs with filtering (Protected)"""
try:
@@ -99,7 +106,7 @@ def get_marketplace_import_jobs(
marketplace=marketplace,
shop_name=shop_name,
skip=skip,
limit=limit
limit=limit,
)
return [marketplace_service.convert_to_response_model(job) for job in jobs]
@@ -111,8 +118,7 @@ def get_marketplace_import_jobs(
@router.get("/marketplace/marketplace-import-stats")
def get_marketplace_import_stats(
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
db: Session = Depends(get_db), current_user: User = Depends(get_current_user)
):
"""Get statistics about marketplace import jobs (Protected)"""
try:
@@ -124,11 +130,14 @@ def get_marketplace_import_stats(
raise HTTPException(status_code=500, detail="Internal server error")
@router.put("/marketplace/import-jobs/{job_id}/cancel", response_model=MarketplaceImportJobResponse)
@router.put(
"/marketplace/import-jobs/{job_id}/cancel",
response_model=MarketplaceImportJobResponse,
)
def cancel_marketplace_import_job(
job_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
job_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Cancel a pending or running marketplace import job (Protected)"""
try:
@@ -146,9 +155,9 @@ def cancel_marketplace_import_job(
@router.delete("/marketplace/import-jobs/{job_id}")
def delete_marketplace_import_job(
job_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
job_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Delete a completed marketplace import job (Protected)"""
try:

View File

@@ -1,17 +1,17 @@
import logging
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.api.deps import get_current_user
from models.api_models import (ProductListResponse, ProductResponse, ProductCreate, ProductDetailResponse,
from app.core.database import get_db
from app.services.product_service import product_service
from models.api_models import (ProductCreate, ProductDetailResponse,
ProductListResponse, ProductResponse,
ProductUpdate)
from models.database_models import User
import logging
from app.services.product_service import product_service
router = APIRouter()
logger = logging.getLogger(__name__)
@@ -20,16 +20,16 @@ logger = logging.getLogger(__name__)
# Enhanced Product Routes with Marketplace Support
@router.get("/product", response_model=ProductListResponse)
def get_products(
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
brand: Optional[str] = Query(None),
category: Optional[str] = Query(None),
availability: Optional[str] = Query(None),
marketplace: Optional[str] = Query(None, description="Filter by marketplace"),
shop_name: Optional[str] = Query(None, description="Filter by shop name"),
search: Optional[str] = Query(None),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
brand: Optional[str] = Query(None),
category: Optional[str] = Query(None),
availability: Optional[str] = Query(None),
marketplace: Optional[str] = Query(None, description="Filter by marketplace"),
shop_name: Optional[str] = Query(None, description="Filter by shop name"),
search: Optional[str] = Query(None),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get products with advanced filtering including marketplace and shop (Protected)"""
@@ -43,14 +43,11 @@ def get_products(
availability=availability,
marketplace=marketplace,
shop_name=shop_name,
search=search
search=search,
)
return ProductListResponse(
products=products,
total=total,
skip=skip,
limit=limit
products=products, total=total, skip=skip, limit=limit
)
except Exception as e:
logger.error(f"Error getting products: {str(e)}")
@@ -59,9 +56,9 @@ def get_products(
@router.post("/product", response_model=ProductResponse)
def create_product(
product: ProductCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
product: ProductCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Create a new product with validation and marketplace support (Protected)"""
@@ -75,7 +72,9 @@ def create_product(
if existing:
logger.info("Product already exists, raising 400 error")
raise HTTPException(status_code=400, detail="Product with this ID already exists")
raise HTTPException(
status_code=400, detail="Product with this ID already exists"
)
logger.info("No existing product found, proceeding to create...")
db_product = product_service.create_product(db, product)
@@ -93,11 +92,12 @@ def create_product(
logger.error(f"Unexpected error: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail="Internal server error")
@router.get("/product/{product_id}", response_model=ProductDetailResponse)
def get_product(
product_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
product_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get product with stock information (Protected)"""
@@ -111,10 +111,7 @@ def get_product(
if product.gtin:
stock_info = product_service.get_stock_info(db, product.gtin)
return ProductDetailResponse(
product=product,
stock_info=stock_info
)
return ProductDetailResponse(product=product, stock_info=stock_info)
except HTTPException:
raise
@@ -125,10 +122,10 @@ def get_product(
@router.put("/product/{product_id}", response_model=ProductResponse)
def update_product(
product_id: str,
product_update: ProductUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
product_id: str,
product_update: ProductUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Update product with validation and marketplace support (Protected)"""
@@ -151,9 +148,9 @@ def update_product(
@router.delete("/product/{product_id}")
def delete_product(
product_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
product_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Delete product and associated stock (Protected)"""
@@ -176,19 +173,18 @@ def delete_product(
# Export with streaming for large datasets (Protected)
@router.get("/export-csv")
async def export_csv(
marketplace: Optional[str] = Query(None, description="Filter by marketplace"),
shop_name: Optional[str] = Query(None, description="Filter by shop name"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
marketplace: Optional[str] = Query(None, description="Filter by marketplace"),
shop_name: Optional[str] = Query(None, description="Filter by shop name"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Export products as CSV with streaming and marketplace filtering (Protected)"""
try:
def generate_csv():
return product_service.generate_csv_export(
db=db,
marketplace=marketplace,
shop_name=shop_name
db=db, marketplace=marketplace, shop_name=shop_name
)
filename = "products_export"
@@ -201,7 +197,7 @@ async def export_csv(
return StreamingResponse(
generate_csv(),
media_type="text/csv",
headers={"Content-Disposition": f"attachment; filename={filename}"}
headers={"Content-Disposition": f"attachment; filename={filename}"},
)
except Exception as e:

View File

@@ -1,17 +1,21 @@
import logging
from datetime import datetime
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query, BackgroundTasks
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.api.deps import get_current_user, get_user_shop
from app.core.database import get_db
from app.services.shop_service import shop_service
from app.tasks.background_tasks import process_marketplace_import
from middleware.decorators import rate_limit
from models.api_models import MarketplaceImportJobResponse, MarketplaceImportRequest, ShopResponse, ShopCreate, \
ShopListResponse, ShopProductResponse, ShopProductCreate
from models.database_models import User, MarketplaceImportJob, Shop, Product, ShopProduct
from datetime import datetime
import logging
from models.api_models import (MarketplaceImportJobResponse,
MarketplaceImportRequest, ShopCreate,
ShopListResponse, ShopProductCreate,
ShopProductResponse, ShopResponse)
from models.database_models import (MarketplaceImportJob, Product, Shop,
ShopProduct, User)
router = APIRouter()
logger = logging.getLogger(__name__)
@@ -20,13 +24,15 @@ logger = logging.getLogger(__name__)
# Shop Management Routes
@router.post("/shop", response_model=ShopResponse)
def create_shop(
shop_data: ShopCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
shop_data: ShopCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Create a new shop (Protected)"""
try:
shop = shop_service.create_shop(db=db, shop_data=shop_data, current_user=current_user)
shop = shop_service.create_shop(
db=db, shop_data=shop_data, current_user=current_user
)
return ShopResponse.model_validate(shop)
except HTTPException:
raise
@@ -37,12 +43,12 @@ def create_shop(
@router.get("/shop", response_model=ShopListResponse)
def get_shops(
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
active_only: bool = Query(True),
verified_only: bool = Query(False),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
active_only: bool = Query(True),
verified_only: bool = Query(False),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get shops with filtering (Protected)"""
try:
@@ -52,15 +58,10 @@ def get_shops(
skip=skip,
limit=limit,
active_only=active_only,
verified_only=verified_only
verified_only=verified_only,
)
return ShopListResponse(
shops=shops,
total=total,
skip=skip,
limit=limit
)
return ShopListResponse(shops=shops, total=total, skip=skip, limit=limit)
except HTTPException:
raise
except Exception as e:
@@ -69,10 +70,16 @@ def get_shops(
@router.get("/shop/{shop_code}", response_model=ShopResponse)
def get_shop(shop_code: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)):
def get_shop(
shop_code: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get shop details (Protected)"""
try:
shop = shop_service.get_shop_by_code(db=db, shop_code=shop_code, current_user=current_user)
shop = shop_service.get_shop_by_code(
db=db, shop_code=shop_code, current_user=current_user
)
return ShopResponse.model_validate(shop)
except HTTPException:
raise
@@ -84,10 +91,10 @@ def get_shop(shop_code: str, db: Session = Depends(get_db), current_user: User =
# Shop Product Management
@router.post("/shop/{shop_code}/products", response_model=ShopProductResponse)
def add_product_to_shop(
shop_code: str,
shop_product: ShopProductCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
shop_code: str,
shop_product: ShopProductCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Add existing product to shop catalog with shop-specific settings (Protected)"""
try:
@@ -96,9 +103,7 @@ def add_product_to_shop(
# Add product to shop
new_shop_product = shop_service.add_product_to_shop(
db=db,
shop=shop,
shop_product=shop_product
db=db, shop=shop, shop_product=shop_product
)
# Return with product details
@@ -114,18 +119,20 @@ def add_product_to_shop(
@router.get("/shop/{shop_code}/products")
def get_shop_products(
shop_code: str,
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
active_only: bool = Query(True),
featured_only: bool = Query(False),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
shop_code: str,
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
active_only: bool = Query(True),
featured_only: bool = Query(False),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get products in shop catalog (Protected)"""
try:
# Get shop
shop = shop_service.get_shop_by_code(db=db, shop_code=shop_code, current_user=current_user)
shop = shop_service.get_shop_by_code(
db=db, shop_code=shop_code, current_user=current_user
)
# Get shop products
shop_products, total = shop_service.get_shop_products(
@@ -135,7 +142,7 @@ def get_shop_products(
skip=skip,
limit=limit,
active_only=active_only,
featured_only=featured_only
featured_only=featured_only,
)
# Format response
@@ -150,7 +157,7 @@ def get_shop_products(
"total": total,
"skip": skip,
"limit": limit,
"shop": ShopResponse.model_validate(shop)
"shop": ShopResponse.model_validate(shop),
}
except HTTPException:
raise

View File

@@ -1,18 +1,21 @@
import logging
from datetime import datetime
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query, BackgroundTasks
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query
from sqlalchemy import func
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.api.deps import get_current_user
from app.core.database import get_db
from app.services.stats_service import stats_service
from app.tasks.background_tasks import process_marketplace_import
from middleware.decorators import rate_limit
from models.api_models import MarketplaceImportJobResponse, MarketplaceImportRequest, StatsResponse, \
MarketplaceStatsResponse
from models.database_models import User, MarketplaceImportJob, Shop, Product, Stock
from datetime import datetime
import logging
from models.api_models import (MarketplaceImportJobResponse,
MarketplaceImportRequest,
MarketplaceStatsResponse, StatsResponse)
from models.database_models import (MarketplaceImportJob, Product, Shop, Stock,
User)
router = APIRouter()
logger = logging.getLogger(__name__)
@@ -20,7 +23,9 @@ logger = logging.getLogger(__name__)
# Enhanced Statistics with Marketplace Support
@router.get("/stats", response_model=StatsResponse)
def get_stats(db: Session = Depends(get_db), current_user: User = Depends(get_current_user)):
def get_stats(
db: Session = Depends(get_db), current_user: User = Depends(get_current_user)
):
"""Get comprehensive statistics with marketplace data (Protected)"""
try:
stats_data = stats_service.get_comprehensive_stats(db=db)
@@ -32,7 +37,7 @@ def get_stats(db: Session = Depends(get_db), current_user: User = Depends(get_cu
unique_marketplaces=stats_data["unique_marketplaces"],
unique_shops=stats_data["unique_shops"],
total_stock_entries=stats_data["total_stock_entries"],
total_inventory_quantity=stats_data["total_inventory_quantity"]
total_inventory_quantity=stats_data["total_inventory_quantity"],
)
except Exception as e:
logger.error(f"Error getting comprehensive stats: {str(e)}")
@@ -40,7 +45,9 @@ def get_stats(db: Session = Depends(get_db), current_user: User = Depends(get_cu
@router.get("/stats/marketplace", response_model=List[MarketplaceStatsResponse])
def get_marketplace_stats(db: Session = Depends(get_db), current_user: User = Depends(get_current_user)):
def get_marketplace_stats(
db: Session = Depends(get_db), current_user: User = Depends(get_current_user)
):
"""Get statistics broken down by marketplace (Protected)"""
try:
marketplace_stats = stats_service.get_marketplace_breakdown_stats(db=db)
@@ -50,8 +57,9 @@ def get_marketplace_stats(db: Session = Depends(get_db), current_user: User = De
marketplace=stat["marketplace"],
total_products=stat["total_products"],
unique_shops=stat["unique_shops"],
unique_brands=stat["unique_brands"]
) for stat in marketplace_stats
unique_brands=stat["unique_brands"],
)
for stat in marketplace_stats
]
except Exception as e:
logger.error(f"Error getting marketplace stats: {str(e)}")

View File

@@ -1,16 +1,19 @@
import logging
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query, BackgroundTasks
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.api.deps import get_current_user
from app.core.database import get_db
from app.services.stock_service import stock_service
from app.tasks.background_tasks import process_marketplace_import
from middleware.decorators import rate_limit
from models.api_models import (MarketplaceImportJobResponse, MarketplaceImportRequest, StockResponse,
StockSummaryResponse, StockCreate, StockAdd, StockUpdate)
from models.database_models import User, MarketplaceImportJob, Shop
from app.services.stock_service import stock_service
import logging
from models.api_models import (MarketplaceImportJobResponse,
MarketplaceImportRequest, StockAdd, StockCreate,
StockResponse, StockSummaryResponse,
StockUpdate)
from models.database_models import MarketplaceImportJob, Shop, User
router = APIRouter()
logger = logging.getLogger(__name__)
@@ -18,11 +21,12 @@ logger = logging.getLogger(__name__)
# Stock Management Routes (Protected)
@router.post("/stock", response_model=StockResponse)
def set_stock(
stock: StockCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
stock: StockCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Set exact stock quantity for a GTIN at a specific location (replaces existing quantity)"""
try:
@@ -37,9 +41,9 @@ def set_stock(
@router.post("/stock/add", response_model=StockResponse)
def add_stock(
stock: StockAdd,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
stock: StockAdd,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Add quantity to existing stock for a GTIN at a specific location (adds to existing quantity)"""
try:
@@ -54,9 +58,9 @@ def add_stock(
@router.post("/stock/remove", response_model=StockResponse)
def remove_stock(
stock: StockAdd,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
stock: StockAdd,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Remove quantity from existing stock for a GTIN at a specific location"""
try:
@@ -71,9 +75,9 @@ def remove_stock(
@router.get("/stock/{gtin}", response_model=StockSummaryResponse)
def get_stock_by_gtin(
gtin: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
gtin: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get all stock locations and total quantity for a specific GTIN"""
try:
@@ -88,9 +92,9 @@ def get_stock_by_gtin(
@router.get("/stock/{gtin}/total")
def get_total_stock(
gtin: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
gtin: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get total quantity in stock for a specific GTIN"""
try:
@@ -105,21 +109,17 @@ def get_total_stock(
@router.get("/stock", response_model=List[StockResponse])
def get_all_stock(
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
location: Optional[str] = Query(None, description="Filter by location"),
gtin: Optional[str] = Query(None, description="Filter by GTIN"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
location: Optional[str] = Query(None, description="Filter by location"),
gtin: Optional[str] = Query(None, description="Filter by GTIN"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get all stock entries with optional filtering"""
try:
result = stock_service.get_all_stock(
db=db,
skip=skip,
limit=limit,
location=location,
gtin=gtin
db=db, skip=skip, limit=limit, location=location, gtin=gtin
)
return result
except Exception as e:
@@ -129,10 +129,10 @@ def get_all_stock(
@router.put("/stock/{stock_id}", response_model=StockResponse)
def update_stock(
stock_id: int,
stock_update: StockUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
stock_id: int,
stock_update: StockUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Update stock quantity for a specific stock entry"""
try:
@@ -147,9 +147,9 @@ def update_stock(
@router.delete("/stock/{stock_id}")
def delete_stock(
stock_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
stock_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Delete a stock entry"""
try: