style: apply black and isort formatting across entire codebase
- Standardize quote style (single to double quotes) - Reorder and group imports alphabetically - Fix line breaks and indentation for consistency - Apply PEP 8 formatting standards Also updated Makefile to exclude both venv and .venv from code quality checks. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -10,25 +10,21 @@ This module provides:
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Any, Dict, List
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.exceptions import (
|
||||
VendorNotFoundException,
|
||||
AdminOperationException,
|
||||
)
|
||||
|
||||
from models.database.marketplace_product import MarketplaceProduct
|
||||
from models.database.product import Product
|
||||
from models.database.inventory import Inventory
|
||||
from models.database.vendor import Vendor
|
||||
from models.database.order import Order
|
||||
from models.database.user import User
|
||||
from app.exceptions import AdminOperationException, VendorNotFoundException
|
||||
from models.database.customer import Customer
|
||||
from models.database.inventory import Inventory
|
||||
from models.database.marketplace_import_job import MarketplaceImportJob
|
||||
from models.database.marketplace_product import MarketplaceProduct
|
||||
from models.database.order import Order
|
||||
from models.database.product import Product
|
||||
from models.database.user import User
|
||||
from models.database.vendor import Vendor
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -62,63 +58,77 @@ class StatsService:
|
||||
|
||||
try:
|
||||
# Catalog statistics
|
||||
total_catalog_products = db.query(Product).filter(
|
||||
Product.vendor_id == vendor_id,
|
||||
Product.is_active == True
|
||||
).count()
|
||||
total_catalog_products = (
|
||||
db.query(Product)
|
||||
.filter(Product.vendor_id == vendor_id, Product.is_active == True)
|
||||
.count()
|
||||
)
|
||||
|
||||
featured_products = db.query(Product).filter(
|
||||
Product.vendor_id == vendor_id,
|
||||
Product.is_featured == True,
|
||||
Product.is_active == True
|
||||
).count()
|
||||
featured_products = (
|
||||
db.query(Product)
|
||||
.filter(
|
||||
Product.vendor_id == vendor_id,
|
||||
Product.is_featured == True,
|
||||
Product.is_active == True,
|
||||
)
|
||||
.count()
|
||||
)
|
||||
|
||||
# Staging statistics
|
||||
# TODO: This is fragile - MarketplaceProduct uses vendor_name (string) not vendor_id
|
||||
# Should add vendor_id foreign key to MarketplaceProduct for robust querying
|
||||
# For now, matching by vendor name which could fail if names don't match exactly
|
||||
staging_products = db.query(MarketplaceProduct).filter(
|
||||
MarketplaceProduct.vendor_name == vendor.name
|
||||
).count()
|
||||
staging_products = (
|
||||
db.query(MarketplaceProduct)
|
||||
.filter(MarketplaceProduct.vendor_name == vendor.name)
|
||||
.count()
|
||||
)
|
||||
|
||||
# Inventory statistics
|
||||
total_inventory = db.query(
|
||||
func.sum(Inventory.quantity)
|
||||
).filter(
|
||||
Inventory.vendor_id == vendor_id
|
||||
).scalar() or 0
|
||||
total_inventory = (
|
||||
db.query(func.sum(Inventory.quantity))
|
||||
.filter(Inventory.vendor_id == vendor_id)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
|
||||
reserved_inventory = db.query(
|
||||
func.sum(Inventory.reserved_quantity)
|
||||
).filter(
|
||||
Inventory.vendor_id == vendor_id
|
||||
).scalar() or 0
|
||||
reserved_inventory = (
|
||||
db.query(func.sum(Inventory.reserved_quantity))
|
||||
.filter(Inventory.vendor_id == vendor_id)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
|
||||
inventory_locations = db.query(
|
||||
func.count(func.distinct(Inventory.location))
|
||||
).filter(
|
||||
Inventory.vendor_id == vendor_id
|
||||
).scalar() or 0
|
||||
inventory_locations = (
|
||||
db.query(func.count(func.distinct(Inventory.location)))
|
||||
.filter(Inventory.vendor_id == vendor_id)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
|
||||
# Import statistics
|
||||
total_imports = db.query(MarketplaceImportJob).filter(
|
||||
MarketplaceImportJob.vendor_id == vendor_id
|
||||
).count()
|
||||
total_imports = (
|
||||
db.query(MarketplaceImportJob)
|
||||
.filter(MarketplaceImportJob.vendor_id == vendor_id)
|
||||
.count()
|
||||
)
|
||||
|
||||
successful_imports = db.query(MarketplaceImportJob).filter(
|
||||
MarketplaceImportJob.vendor_id == vendor_id,
|
||||
MarketplaceImportJob.status == "completed"
|
||||
).count()
|
||||
successful_imports = (
|
||||
db.query(MarketplaceImportJob)
|
||||
.filter(
|
||||
MarketplaceImportJob.vendor_id == vendor_id,
|
||||
MarketplaceImportJob.status == "completed",
|
||||
)
|
||||
.count()
|
||||
)
|
||||
|
||||
# Orders
|
||||
total_orders = db.query(Order).filter(
|
||||
Order.vendor_id == vendor_id
|
||||
).count()
|
||||
total_orders = db.query(Order).filter(Order.vendor_id == vendor_id).count()
|
||||
|
||||
# Customers
|
||||
total_customers = db.query(Customer).filter(
|
||||
Customer.vendor_id == vendor_id
|
||||
).count()
|
||||
total_customers = (
|
||||
db.query(Customer).filter(Customer.vendor_id == vendor_id).count()
|
||||
)
|
||||
|
||||
return {
|
||||
"catalog": {
|
||||
@@ -138,7 +148,11 @@ class StatsService:
|
||||
"imports": {
|
||||
"total_imports": total_imports,
|
||||
"successful_imports": successful_imports,
|
||||
"success_rate": (successful_imports / total_imports * 100) if total_imports > 0 else 0,
|
||||
"success_rate": (
|
||||
(successful_imports / total_imports * 100)
|
||||
if total_imports > 0
|
||||
else 0
|
||||
),
|
||||
},
|
||||
"orders": {
|
||||
"total_orders": total_orders,
|
||||
@@ -151,16 +165,18 @@ class StatsService:
|
||||
except VendorNotFoundException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to retrieve vendor statistics for vendor {vendor_id}: {str(e)}")
|
||||
logger.error(
|
||||
f"Failed to retrieve vendor statistics for vendor {vendor_id}: {str(e)}"
|
||||
)
|
||||
raise AdminOperationException(
|
||||
operation="get_vendor_stats",
|
||||
reason=f"Database query failed: {str(e)}",
|
||||
target_type="vendor",
|
||||
target_id=str(vendor_id)
|
||||
target_id=str(vendor_id),
|
||||
)
|
||||
|
||||
def get_vendor_analytics(
|
||||
self, db: Session, vendor_id: int, period: str = "30d"
|
||||
self, db: Session, vendor_id: int, period: str = "30d"
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Get a specific vendor analytics for a time period.
|
||||
@@ -188,21 +204,28 @@ class StatsService:
|
||||
start_date = datetime.utcnow() - timedelta(days=days)
|
||||
|
||||
# Import activity
|
||||
recent_imports = db.query(MarketplaceImportJob).filter(
|
||||
MarketplaceImportJob.vendor_id == vendor_id,
|
||||
MarketplaceImportJob.created_at >= start_date
|
||||
).count()
|
||||
recent_imports = (
|
||||
db.query(MarketplaceImportJob)
|
||||
.filter(
|
||||
MarketplaceImportJob.vendor_id == vendor_id,
|
||||
MarketplaceImportJob.created_at >= start_date,
|
||||
)
|
||||
.count()
|
||||
)
|
||||
|
||||
# Products added to catalog
|
||||
products_added = db.query(Product).filter(
|
||||
Product.vendor_id == vendor_id,
|
||||
Product.created_at >= start_date
|
||||
).count()
|
||||
products_added = (
|
||||
db.query(Product)
|
||||
.filter(
|
||||
Product.vendor_id == vendor_id, Product.created_at >= start_date
|
||||
)
|
||||
.count()
|
||||
)
|
||||
|
||||
# Inventory changes
|
||||
inventory_entries = db.query(Inventory).filter(
|
||||
Inventory.vendor_id == vendor_id
|
||||
).count()
|
||||
inventory_entries = (
|
||||
db.query(Inventory).filter(Inventory.vendor_id == vendor_id).count()
|
||||
)
|
||||
|
||||
return {
|
||||
"period": period,
|
||||
@@ -221,12 +244,14 @@ class StatsService:
|
||||
except VendorNotFoundException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to retrieve vendor analytics for vendor {vendor_id}: {str(e)}")
|
||||
logger.error(
|
||||
f"Failed to retrieve vendor analytics for vendor {vendor_id}: {str(e)}"
|
||||
)
|
||||
raise AdminOperationException(
|
||||
operation="get_vendor_analytics",
|
||||
reason=f"Database query failed: {str(e)}",
|
||||
target_type="vendor",
|
||||
target_id=str(vendor_id)
|
||||
target_id=str(vendor_id),
|
||||
)
|
||||
|
||||
def get_vendor_statistics(self, db: Session) -> dict:
|
||||
@@ -234,7 +259,9 @@ class StatsService:
|
||||
try:
|
||||
total_vendors = db.query(Vendor).count()
|
||||
active_vendors = db.query(Vendor).filter(Vendor.is_active == True).count()
|
||||
verified_vendors = db.query(Vendor).filter(Vendor.is_verified == True).count()
|
||||
verified_vendors = (
|
||||
db.query(Vendor).filter(Vendor.is_verified == True).count()
|
||||
)
|
||||
inactive_vendors = total_vendors - active_vendors
|
||||
|
||||
return {
|
||||
@@ -242,13 +269,14 @@ class StatsService:
|
||||
"active_vendors": active_vendors,
|
||||
"inactive_vendors": inactive_vendors,
|
||||
"verified_vendors": verified_vendors,
|
||||
"verification_rate": (verified_vendors / total_vendors * 100) if total_vendors > 0 else 0
|
||||
"verification_rate": (
|
||||
(verified_vendors / total_vendors * 100) if total_vendors > 0 else 0
|
||||
),
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get vendor statistics: {str(e)}")
|
||||
raise AdminOperationException(
|
||||
operation="get_vendor_statistics",
|
||||
reason="Database query failed"
|
||||
operation="get_vendor_statistics", reason="Database query failed"
|
||||
)
|
||||
|
||||
# ========================================================================
|
||||
@@ -302,7 +330,7 @@ class StatsService:
|
||||
logger.error(f"Failed to retrieve comprehensive statistics: {str(e)}")
|
||||
raise AdminOperationException(
|
||||
operation="get_comprehensive_stats",
|
||||
reason=f"Database query failed: {str(e)}"
|
||||
reason=f"Database query failed: {str(e)}",
|
||||
)
|
||||
|
||||
def get_marketplace_breakdown_stats(self, db: Session) -> List[Dict[str, Any]]:
|
||||
@@ -323,8 +351,12 @@ class StatsService:
|
||||
db.query(
|
||||
MarketplaceProduct.marketplace,
|
||||
func.count(MarketplaceProduct.id).label("total_products"),
|
||||
func.count(func.distinct(MarketplaceProduct.vendor_name)).label("unique_vendors"),
|
||||
func.count(func.distinct(MarketplaceProduct.brand)).label("unique_brands"),
|
||||
func.count(func.distinct(MarketplaceProduct.vendor_name)).label(
|
||||
"unique_vendors"
|
||||
),
|
||||
func.count(func.distinct(MarketplaceProduct.brand)).label(
|
||||
"unique_brands"
|
||||
),
|
||||
)
|
||||
.filter(MarketplaceProduct.marketplace.isnot(None))
|
||||
.group_by(MarketplaceProduct.marketplace)
|
||||
@@ -342,10 +374,12 @@ class StatsService:
|
||||
]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to retrieve marketplace breakdown statistics: {str(e)}")
|
||||
logger.error(
|
||||
f"Failed to retrieve marketplace breakdown statistics: {str(e)}"
|
||||
)
|
||||
raise AdminOperationException(
|
||||
operation="get_marketplace_breakdown_stats",
|
||||
reason=f"Database query failed: {str(e)}"
|
||||
reason=f"Database query failed: {str(e)}",
|
||||
)
|
||||
|
||||
def get_user_statistics(self, db: Session) -> Dict[str, Any]:
|
||||
@@ -372,13 +406,14 @@ class StatsService:
|
||||
"active_users": active_users,
|
||||
"inactive_users": inactive_users,
|
||||
"admin_users": admin_users,
|
||||
"activation_rate": (active_users / total_users * 100) if total_users > 0 else 0
|
||||
"activation_rate": (
|
||||
(active_users / total_users * 100) if total_users > 0 else 0
|
||||
),
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get user statistics: {str(e)}")
|
||||
raise AdminOperationException(
|
||||
operation="get_user_statistics",
|
||||
reason="Database query failed"
|
||||
operation="get_user_statistics", reason="Database query failed"
|
||||
)
|
||||
|
||||
def get_import_statistics(self, db: Session) -> Dict[str, Any]:
|
||||
@@ -396,18 +431,22 @@ class StatsService:
|
||||
"""
|
||||
try:
|
||||
total = db.query(MarketplaceImportJob).count()
|
||||
completed = db.query(MarketplaceImportJob).filter(
|
||||
MarketplaceImportJob.status == "completed"
|
||||
).count()
|
||||
failed = db.query(MarketplaceImportJob).filter(
|
||||
MarketplaceImportJob.status == "failed"
|
||||
).count()
|
||||
completed = (
|
||||
db.query(MarketplaceImportJob)
|
||||
.filter(MarketplaceImportJob.status == "completed")
|
||||
.count()
|
||||
)
|
||||
failed = (
|
||||
db.query(MarketplaceImportJob)
|
||||
.filter(MarketplaceImportJob.status == "failed")
|
||||
.count()
|
||||
)
|
||||
|
||||
return {
|
||||
"total_imports": total,
|
||||
"completed_imports": completed,
|
||||
"failed_imports": failed,
|
||||
"success_rate": (completed / total * 100) if total > 0 else 0
|
||||
"success_rate": (completed / total * 100) if total > 0 else 0,
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get import statistics: {str(e)}")
|
||||
@@ -415,7 +454,7 @@ class StatsService:
|
||||
"total_imports": 0,
|
||||
"completed_imports": 0,
|
||||
"failed_imports": 0,
|
||||
"success_rate": 0
|
||||
"success_rate": 0,
|
||||
}
|
||||
|
||||
def get_order_statistics(self, db: Session) -> Dict[str, Any]:
|
||||
@@ -431,11 +470,7 @@ class StatsService:
|
||||
Note:
|
||||
TODO: Implement when Order model is fully available
|
||||
"""
|
||||
return {
|
||||
"total_orders": 0,
|
||||
"pending_orders": 0,
|
||||
"completed_orders": 0
|
||||
}
|
||||
return {"total_orders": 0, "pending_orders": 0, "completed_orders": 0}
|
||||
|
||||
def get_product_statistics(self, db: Session) -> Dict[str, Any]:
|
||||
"""
|
||||
@@ -450,11 +485,7 @@ class StatsService:
|
||||
Note:
|
||||
TODO: Implement when Product model is fully available
|
||||
"""
|
||||
return {
|
||||
"total_products": 0,
|
||||
"active_products": 0,
|
||||
"out_of_stock": 0
|
||||
}
|
||||
return {"total_products": 0, "active_products": 0, "out_of_stock": 0}
|
||||
|
||||
# ========================================================================
|
||||
# PRIVATE HELPER METHODS
|
||||
@@ -491,8 +522,7 @@ class StatsService:
|
||||
return (
|
||||
db.query(MarketplaceProduct.brand)
|
||||
.filter(
|
||||
MarketplaceProduct.brand.isnot(None),
|
||||
MarketplaceProduct.brand != ""
|
||||
MarketplaceProduct.brand.isnot(None), MarketplaceProduct.brand != ""
|
||||
)
|
||||
.distinct()
|
||||
.count()
|
||||
|
||||
Reference in New Issue
Block a user