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:
2025-11-28 19:30:17 +01:00
parent 13f0094743
commit 21c13ca39b
236 changed files with 8450 additions and 6545 deletions

View File

@@ -21,7 +21,7 @@ Authentication:
from fastapi import APIRouter
# Import shop routers
from . import products, cart, orders, auth, content_pages
from . import auth, cart, content_pages, orders, products
# Create shop router
router = APIRouter()
@@ -43,6 +43,8 @@ router.include_router(cart.router, tags=["shop-cart"])
router.include_router(orders.router, tags=["shop-orders"])
# Content pages (public)
router.include_router(content_pages.router, prefix="/content-pages", tags=["shop-content-pages"])
router.include_router(
content_pages.router, prefix="/content-pages", tags=["shop-content-pages"]
)
__all__ = ["router"]

View File

@@ -15,15 +15,16 @@ This prevents:
"""
import logging
from fastapi import APIRouter, Depends, Response, Request, HTTPException
from fastapi import APIRouter, Depends, HTTPException, Request, Response
from pydantic import BaseModel
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.environment import should_use_secure_cookies
from app.services.customer_service import customer_service
from models.schema.auth import UserLogin
from models.schema.customer import CustomerRegister, CustomerResponse
from app.core.environment import should_use_secure_cookies
from pydantic import BaseModel
router = APIRouter()
logger = logging.getLogger(__name__)
@@ -32,6 +33,7 @@ logger = logging.getLogger(__name__)
# Response model for customer login
class CustomerLoginResponse(BaseModel):
"""Customer login response with token and customer data."""
access_token: str
token_type: str
expires_in: int
@@ -40,9 +42,7 @@ class CustomerLoginResponse(BaseModel):
@router.post("/auth/register", response_model=CustomerResponse)
def register_customer(
request: Request,
customer_data: CustomerRegister,
db: Session = Depends(get_db)
request: Request, customer_data: CustomerRegister, db: Session = Depends(get_db)
):
"""
Register a new customer for current vendor.
@@ -59,12 +59,12 @@ def register_customer(
- phone: Customer phone number (optional)
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
logger.debug(
@@ -73,14 +73,12 @@ def register_customer(
"vendor_id": vendor.id,
"vendor_code": vendor.subdomain,
"email": customer_data.email,
}
},
)
# Create customer account
customer = customer_service.register_customer(
db=db,
vendor_id=vendor.id,
customer_data=customer_data
db=db, vendor_id=vendor.id, customer_data=customer_data
)
logger.info(
@@ -89,7 +87,7 @@ def register_customer(
"customer_id": customer.id,
"vendor_id": vendor.id,
"email": customer.email,
}
},
)
return CustomerResponse.model_validate(customer)
@@ -100,7 +98,7 @@ def customer_login(
request: Request,
user_credentials: UserLogin,
response: Response,
db: Session = Depends(get_db)
db: Session = Depends(get_db),
):
"""
Customer login for current vendor.
@@ -121,12 +119,12 @@ def customer_login(
- password: Customer password
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
logger.debug(
@@ -135,33 +133,39 @@ def customer_login(
"vendor_id": vendor.id,
"vendor_code": vendor.subdomain,
"email_or_username": user_credentials.email_or_username,
}
},
)
# Authenticate customer
login_result = customer_service.login_customer(
db=db,
vendor_id=vendor.id,
credentials=user_credentials
db=db, vendor_id=vendor.id, credentials=user_credentials
)
logger.info(
f"Customer login successful: {login_result['customer'].email} for vendor {vendor.subdomain}",
extra={
"customer_id": login_result['customer'].id,
"customer_id": login_result["customer"].id,
"vendor_id": vendor.id,
"email": login_result['customer'].email,
}
"email": login_result["customer"].email,
},
)
# Calculate cookie path based on vendor access method
vendor_context = getattr(request.state, 'vendor_context', None)
access_method = vendor_context.get('detection_method', 'unknown') if vendor_context else 'unknown'
vendor_context = getattr(request.state, "vendor_context", None)
access_method = (
vendor_context.get("detection_method", "unknown")
if vendor_context
else "unknown"
)
cookie_path = "/shop" # Default for domain/subdomain access
if access_method == "path":
# For path-based access like /vendors/wizamart/shop
full_prefix = vendor_context.get('full_prefix', '/vendor/') if vendor_context else '/vendor/'
full_prefix = (
vendor_context.get("full_prefix", "/vendor/")
if vendor_context
else "/vendor/"
)
cookie_path = f"{full_prefix}{vendor.subdomain}/shop"
# Set HTTP-only cookie for browser navigation
@@ -180,10 +184,10 @@ def customer_login(
f"Set customer_token cookie with {login_result['token_data']['expires_in']}s expiry "
f"(path={cookie_path}, httponly=True, secure={should_use_secure_cookies()})",
extra={
"expires_in": login_result['token_data']['expires_in'],
"expires_in": login_result["token_data"]["expires_in"],
"secure": should_use_secure_cookies(),
"cookie_path": cookie_path,
}
},
)
# Return full login response
@@ -196,10 +200,7 @@ def customer_login(
@router.post("/auth/logout")
def customer_logout(
request: Request,
response: Response
):
def customer_logout(request: Request, response: Response):
"""
Customer logout for current vendor.
@@ -208,24 +209,32 @@ def customer_logout(
Client should also remove token from localStorage.
"""
# Get vendor from middleware (for logging)
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
logger.info(
f"Customer logout for vendor {vendor.subdomain if vendor else 'unknown'}",
extra={
"vendor_id": vendor.id if vendor else None,
"vendor_code": vendor.subdomain if vendor else None,
}
},
)
# Calculate cookie path based on vendor access method (must match login)
vendor_context = getattr(request.state, 'vendor_context', None)
access_method = vendor_context.get('detection_method', 'unknown') if vendor_context else 'unknown'
vendor_context = getattr(request.state, "vendor_context", None)
access_method = (
vendor_context.get("detection_method", "unknown")
if vendor_context
else "unknown"
)
cookie_path = "/shop" # Default for domain/subdomain access
if access_method == "path" and vendor:
# For path-based access like /vendors/wizamart/shop
full_prefix = vendor_context.get('full_prefix', '/vendor/') if vendor_context else '/vendor/'
full_prefix = (
vendor_context.get("full_prefix", "/vendor/")
if vendor_context
else "/vendor/"
)
cookie_path = f"{full_prefix}{vendor.subdomain}/shop"
# Clear the cookie (must match path used when setting)
@@ -240,11 +249,7 @@ def customer_logout(
@router.post("/auth/forgot-password")
def forgot_password(
request: Request,
email: str,
db: Session = Depends(get_db)
):
def forgot_password(request: Request, email: str, db: Session = Depends(get_db)):
"""
Request password reset for customer.
@@ -255,12 +260,12 @@ def forgot_password(
- email: Customer email address
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
logger.debug(
@@ -269,7 +274,7 @@ def forgot_password(
"vendor_id": vendor.id,
"vendor_code": vendor.subdomain,
"email": email,
}
},
)
# TODO: Implement password reset functionality
@@ -278,9 +283,7 @@ def forgot_password(
# - Send reset email to customer
# - Return success message (don't reveal if email exists)
logger.info(
f"Password reset requested for {email} (vendor: {vendor.subdomain})"
)
logger.info(f"Password reset requested for {email} (vendor: {vendor.subdomain})")
return {
"message": "If an account exists with this email, a password reset link has been sent."
@@ -289,10 +292,7 @@ def forgot_password(
@router.post("/auth/reset-password")
def reset_password(
request: Request,
reset_token: str,
new_password: str,
db: Session = Depends(get_db)
request: Request, reset_token: str, new_password: str, db: Session = Depends(get_db)
):
"""
Reset customer password using reset token.
@@ -304,12 +304,12 @@ def reset_password(
- new_password: New password
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
logger.debug(
@@ -317,7 +317,7 @@ def reset_password(
extra={
"vendor_id": vendor.id,
"vendor_code": vendor.subdomain,
}
},
)
# TODO: Implement password reset
@@ -327,9 +327,7 @@ def reset_password(
# - Invalidate reset token
# - Return success
logger.info(
f"Password reset completed (vendor: {vendor.subdomain})"
)
logger.info(f"Password reset completed (vendor: {vendor.subdomain})")
return {
"message": "Password reset successfully. You can now log in with your new password."

View File

@@ -8,18 +8,15 @@ No authentication required - uses session ID for cart tracking.
"""
import logging
from fastapi import APIRouter, Depends, Path, Body, Request, HTTPException
from fastapi import APIRouter, Body, Depends, HTTPException, Path, Request
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.services.cart_service import cart_service
from models.schema.cart import (
AddToCartRequest,
UpdateCartItemRequest,
CartResponse,
CartOperationResponse,
ClearCartResponse,
)
from models.schema.cart import (AddToCartRequest, CartOperationResponse,
CartResponse, ClearCartResponse,
UpdateCartItemRequest)
router = APIRouter()
logger = logging.getLogger(__name__)
@@ -29,6 +26,7 @@ logger = logging.getLogger(__name__)
# CART ENDPOINTS
# ============================================================================
@router.get("/cart/{session_id}", response_model=CartResponse)
def get_cart(
request: Request,
@@ -45,12 +43,12 @@ def get_cart(
- session_id: Unique session identifier for the cart
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
logger.info(
@@ -59,23 +57,19 @@ def get_cart(
"vendor_id": vendor.id,
"vendor_code": vendor.subdomain,
"session_id": session_id,
}
},
)
cart = cart_service.get_cart(
db=db,
vendor_id=vendor.id,
session_id=session_id
)
cart = cart_service.get_cart(db=db, vendor_id=vendor.id, session_id=session_id)
logger.info(
f"[SHOP_API] get_cart result: {len(cart.get('items', []))} items in cart",
extra={
"session_id": session_id,
"vendor_id": vendor.id,
"item_count": len(cart.get('items', [])),
"total": cart.get('total', 0),
}
"item_count": len(cart.get("items", [])),
"total": cart.get("total", 0),
},
)
return CartResponse.from_service_dict(cart)
@@ -102,12 +96,12 @@ def add_to_cart(
- quantity: Quantity to add (default: 1)
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
logger.info(
@@ -118,7 +112,7 @@ def add_to_cart(
"session_id": session_id,
"product_id": cart_data.product_id,
"quantity": cart_data.quantity,
}
},
)
result = cart_service.add_to_cart(
@@ -126,7 +120,7 @@ def add_to_cart(
vendor_id=vendor.id,
session_id=session_id,
product_id=cart_data.product_id,
quantity=cart_data.quantity
quantity=cart_data.quantity,
)
logger.info(
@@ -134,13 +128,15 @@ def add_to_cart(
extra={
"session_id": session_id,
"result": result,
}
},
)
return CartOperationResponse(**result)
@router.put("/cart/{session_id}/items/{product_id}", response_model=CartOperationResponse)
@router.put(
"/cart/{session_id}/items/{product_id}", response_model=CartOperationResponse
)
def update_cart_item(
request: Request,
session_id: str = Path(..., description="Shopping session ID"),
@@ -162,12 +158,12 @@ def update_cart_item(
- quantity: New quantity (must be >= 1)
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
logger.debug(
@@ -178,7 +174,7 @@ def update_cart_item(
"session_id": session_id,
"product_id": product_id,
"quantity": cart_data.quantity,
}
},
)
result = cart_service.update_cart_item(
@@ -186,13 +182,15 @@ def update_cart_item(
vendor_id=vendor.id,
session_id=session_id,
product_id=product_id,
quantity=cart_data.quantity
quantity=cart_data.quantity,
)
return CartOperationResponse(**result)
@router.delete("/cart/{session_id}/items/{product_id}", response_model=CartOperationResponse)
@router.delete(
"/cart/{session_id}/items/{product_id}", response_model=CartOperationResponse
)
def remove_from_cart(
request: Request,
session_id: str = Path(..., description="Shopping session ID"),
@@ -210,12 +208,12 @@ def remove_from_cart(
- product_id: ID of product to remove
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
logger.debug(
@@ -225,14 +223,11 @@ def remove_from_cart(
"vendor_code": vendor.subdomain,
"session_id": session_id,
"product_id": product_id,
}
},
)
result = cart_service.remove_from_cart(
db=db,
vendor_id=vendor.id,
session_id=session_id,
product_id=product_id
db=db, vendor_id=vendor.id, session_id=session_id, product_id=product_id
)
return CartOperationResponse(**result)
@@ -254,12 +249,12 @@ def clear_cart(
- session_id: Unique session identifier for the cart
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
logger.debug(
@@ -268,13 +263,9 @@ def clear_cart(
"vendor_id": vendor.id,
"vendor_code": vendor.subdomain,
"session_id": session_id,
}
},
)
result = cart_service.clear_cart(
db=db,
vendor_id=vendor.id,
session_id=session_id
)
result = cart_service.clear_cart(db=db, vendor_id=vendor.id, session_id=session_id)
return ClearCartResponse(**result)

View File

@@ -8,6 +8,7 @@ No authentication required.
import logging
from typing import List
from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel
from sqlalchemy.orm import Session
@@ -23,8 +24,10 @@ logger = logging.getLogger(__name__)
# RESPONSE SCHEMAS
# ============================================================================
class PublicContentPageResponse(BaseModel):
"""Public content page response (no internal IDs)."""
slug: str
title: str
content: str
@@ -36,6 +39,7 @@ class PublicContentPageResponse(BaseModel):
class ContentPageListItem(BaseModel):
"""Content page list item for navigation."""
slug: str
title: str
show_in_footer: bool
@@ -47,25 +51,21 @@ class ContentPageListItem(BaseModel):
# PUBLIC ENDPOINTS
# ============================================================================
@router.get("/navigation", response_model=List[ContentPageListItem])
def get_navigation_pages(
request: Request,
db: Session = Depends(get_db)
):
def get_navigation_pages(request: Request, db: Session = Depends(get_db)):
"""
Get list of content pages for navigation (footer/header).
Uses vendor from request.state (set by middleware).
Returns vendor overrides + platform defaults.
"""
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
vendor_id = vendor.id if vendor else None
# Get all published pages for this vendor
pages = content_page_service.list_pages_for_vendor(
db,
vendor_id=vendor_id,
include_unpublished=False
db, vendor_id=vendor_id, include_unpublished=False
)
return [
@@ -81,25 +81,21 @@ def get_navigation_pages(
@router.get("/{slug}", response_model=PublicContentPageResponse)
def get_content_page(
slug: str,
request: Request,
db: Session = Depends(get_db)
):
def get_content_page(slug: str, request: Request, db: Session = Depends(get_db)):
"""
Get a specific content page by slug.
Uses vendor from request.state (set by middleware).
Returns vendor override if exists, otherwise platform default.
"""
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
vendor_id = vendor.id if vendor else None
page = content_page_service.get_page_for_vendor(
db,
slug=slug,
vendor_id=vendor_id,
include_unpublished=False # Only show published pages
include_unpublished=False, # Only show published pages
)
if not page:

View File

@@ -10,31 +10,23 @@ Requires customer authentication for most operations.
import logging
from typing import Optional
from fastapi import APIRouter, Depends, Path, Query, Request, HTTPException
from fastapi import APIRouter, Depends, HTTPException, Path, Query, Request
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.api.deps import get_current_customer_api
from app.services.order_service import order_service
from app.core.database import get_db
from app.services.customer_service import customer_service
from models.schema.order import (
OrderCreate,
OrderResponse,
OrderDetailResponse,
OrderListResponse
)
from models.database.user import User
from app.services.order_service import order_service
from models.database.customer import Customer
from models.database.user import User
from models.schema.order import (OrderCreate, OrderDetailResponse,
OrderListResponse, OrderResponse)
router = APIRouter()
logger = logging.getLogger(__name__)
def get_customer_from_user(
request: Request,
user: User,
db: Session
) -> Customer:
def get_customer_from_user(request: Request, user: User, db: Session) -> Customer:
"""
Helper to get Customer record from authenticated User.
@@ -49,25 +41,22 @@ def get_customer_from_user(
Raises:
HTTPException: If customer not found or vendor mismatch
"""
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
# Find customer record for this user and vendor
customer = customer_service.get_customer_by_user_id(
db=db,
vendor_id=vendor.id,
user_id=user.id
db=db, vendor_id=vendor.id, user_id=user.id
)
if not customer:
raise HTTPException(
status_code=404,
detail="Customer account not found for current vendor"
status_code=404, detail="Customer account not found for current vendor"
)
return customer
@@ -91,12 +80,12 @@ def place_order(
- Order data including shipping address, payment method, etc.
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
# Get customer record
@@ -109,14 +98,12 @@ def place_order(
"vendor_code": vendor.subdomain,
"customer_id": customer.id,
"user_id": current_user.id,
}
},
)
# Create order
order = order_service.create_order(
db=db,
vendor_id=vendor.id,
order_data=order_data
db=db, vendor_id=vendor.id, order_data=order_data
)
logger.info(
@@ -127,7 +114,7 @@ def place_order(
"order_number": order.order_number,
"customer_id": customer.id,
"total_amount": float(order.total_amount),
}
},
)
# TODO: Update customer stats
@@ -156,12 +143,12 @@ def get_my_orders(
- limit: Maximum number of orders to return
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
# Get customer record
@@ -175,23 +162,19 @@ def get_my_orders(
"customer_id": customer.id,
"skip": skip,
"limit": limit,
}
},
)
# Get orders
orders, total = order_service.get_customer_orders(
db=db,
vendor_id=vendor.id,
customer_id=customer.id,
skip=skip,
limit=limit
db=db, vendor_id=vendor.id, customer_id=customer.id, skip=skip, limit=limit
)
return OrderListResponse(
orders=[OrderResponse.model_validate(o) for o in orders],
total=total,
skip=skip,
limit=limit
limit=limit,
)
@@ -212,12 +195,12 @@ def get_order_details(
- order_id: ID of the order to retrieve
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
# Get customer record
@@ -230,19 +213,16 @@ def get_order_details(
"vendor_code": vendor.subdomain,
"customer_id": customer.id,
"order_id": order_id,
}
},
)
# Get order
order = order_service.get_order(
db=db,
vendor_id=vendor.id,
order_id=order_id
)
order = order_service.get_order(db=db, vendor_id=vendor.id, order_id=order_id)
# Verify order belongs to customer
if order.customer_id != customer.id:
from app.exceptions import OrderNotFoundException
raise OrderNotFoundException(str(order_id))
return OrderDetailResponse.model_validate(order)

View File

@@ -10,12 +10,13 @@ No authentication required.
import logging
from typing import Optional
from fastapi import APIRouter, Depends, Query, Path, Request, HTTPException
from fastapi import APIRouter, Depends, HTTPException, Path, Query, Request
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.services.product_service import product_service
from models.schema.product import ProductResponse, ProductDetailResponse, ProductListResponse
from models.schema.product import (ProductDetailResponse, ProductListResponse,
ProductResponse)
router = APIRouter()
logger = logging.getLogger(__name__)
@@ -27,7 +28,9 @@ def get_product_catalog(
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
search: Optional[str] = Query(None, description="Search products by name"),
is_featured: Optional[bool] = Query(None, description="Filter by featured products"),
is_featured: Optional[bool] = Query(
None, description="Filter by featured products"
),
db: Session = Depends(get_db),
):
"""
@@ -44,12 +47,12 @@ def get_product_catalog(
- is_featured: Filter by featured products only
"""
# Get vendor from middleware (injected by VendorContextMiddleware)
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
logger.debug(
@@ -61,7 +64,7 @@ def get_product_catalog(
"limit": limit,
"search": search,
"is_featured": is_featured,
}
},
)
# Get only active products for public view
@@ -71,14 +74,14 @@ def get_product_catalog(
skip=skip,
limit=limit,
is_active=True, # Only show active products to customers
is_featured=is_featured
is_featured=is_featured,
)
return ProductListResponse(
products=[ProductResponse.model_validate(p) for p in products],
total=total,
skip=skip,
limit=limit
limit=limit,
)
@@ -98,12 +101,12 @@ def get_product_details(
- product_id: ID of the product to retrieve
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
logger.debug(
@@ -112,18 +115,17 @@ def get_product_details(
"vendor_id": vendor.id,
"vendor_code": vendor.subdomain,
"product_id": product_id,
}
},
)
product = product_service.get_product(
db=db,
vendor_id=vendor.id,
product_id=product_id
db=db, vendor_id=vendor.id, product_id=product_id
)
# Check if product is active
if not product.is_active:
from app.exceptions import ProductNotActiveException
raise ProductNotActiveException(str(product_id))
return ProductDetailResponse.model_validate(product)
@@ -150,12 +152,12 @@ def search_products(
- limit: Maximum number of results to return
"""
# Get vendor from middleware
vendor = getattr(request.state, 'vendor', None)
vendor = getattr(request.state, "vendor", None)
if not vendor:
raise HTTPException(
status_code=404,
detail="Vendor not found. Please access via vendor domain/subdomain/path."
detail="Vendor not found. Please access via vendor domain/subdomain/path.",
)
logger.debug(
@@ -166,22 +168,18 @@ def search_products(
"query": q,
"skip": skip,
"limit": limit,
}
},
)
# TODO: Implement full-text search functionality
# For now, return filtered products
products, total = product_service.get_vendor_products(
db=db,
vendor_id=vendor.id,
skip=skip,
limit=limit,
is_active=True
db=db, vendor_id=vendor.id, skip=skip, limit=limit, is_active=True
)
return ProductListResponse(
products=[ProductResponse.model_validate(p) for p in products],
total=total,
skip=skip,
limit=limit
limit=limit,
)