Files
orion/app/services/product_service.py
Samir Boulahtit 238c1ec9b8 refactor: modernize code quality tooling with Ruff
- Replace black, isort, and flake8 with Ruff (all-in-one linter and formatter)
- Add comprehensive pyproject.toml configuration
- Simplify Makefile code quality targets
- Configure exclusions for venv/.venv in pyproject.toml
- Auto-fix 1,359 linting issues across codebase

Benefits:
- Much faster builds (Ruff is written in Rust)
- Single tool replaces multiple tools
- More comprehensive rule set (UP, B, C4, SIM, PIE, RET, Q)
- All configuration centralized in pyproject.toml
- Better import sorting and formatting consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 19:37:38 +01:00

259 lines
7.6 KiB
Python

# app/services/product_service.py
"""
Product service for vendor catalog management.
This module provides:
- Product catalog CRUD operations
- Product publishing from marketplace staging
- Product search and filtering
"""
import logging
from datetime import UTC, datetime
from sqlalchemy.orm import Session
from app.exceptions import (
ProductAlreadyExistsException,
ProductNotFoundException,
ValidationException,
)
from models.database.marketplace_product import MarketplaceProduct
from models.database.product import Product
from models.schema.product import ProductCreate, ProductUpdate
logger = logging.getLogger(__name__)
class ProductService:
"""Service for vendor catalog product operations."""
def get_product(self, db: Session, vendor_id: int, product_id: int) -> Product:
"""
Get a product from vendor catalog.
Args:
db: Database session
vendor_id: Vendor ID
product_id: Product ID
Returns:
Product object
Raises:
ProductNotFoundException: If product not found
"""
try:
product = (
db.query(Product)
.filter(Product.id == product_id, Product.vendor_id == vendor_id)
.first()
)
if not product:
raise ProductNotFoundException(f"Product {product_id} not found")
return product
except ProductNotFoundException:
raise
except Exception as e:
logger.error(f"Error getting product: {str(e)}")
raise ValidationException("Failed to retrieve product")
def create_product(
self, db: Session, vendor_id: int, product_data: ProductCreate
) -> Product:
"""
Add a product from marketplace to vendor catalog.
Args:
db: Database session
vendor_id: Vendor ID
product_data: Product creation data
Returns:
Created Product object
Raises:
ProductAlreadyExistsException: If product already in catalog
ValidationException: If marketplace product not found
"""
try:
# Verify marketplace product exists and belongs to vendor
marketplace_product = (
db.query(MarketplaceProduct)
.filter(
MarketplaceProduct.id == product_data.marketplace_product_id,
MarketplaceProduct.vendor_id == vendor_id,
)
.first()
)
if not marketplace_product:
raise ValidationException(
f"Marketplace product {product_data.marketplace_product_id} not found"
)
# Check if already in catalog
existing = (
db.query(Product)
.filter(
Product.vendor_id == vendor_id,
Product.marketplace_product_id
== product_data.marketplace_product_id,
)
.first()
)
if existing:
raise ProductAlreadyExistsException(
"Product already exists in catalog"
)
# Create product
product = Product(
vendor_id=vendor_id,
marketplace_product_id=product_data.marketplace_product_id,
product_id=product_data.product_id,
price=product_data.price,
sale_price=product_data.sale_price,
currency=product_data.currency,
availability=product_data.availability,
condition=product_data.condition,
is_featured=product_data.is_featured,
is_active=True,
min_quantity=product_data.min_quantity,
max_quantity=product_data.max_quantity,
)
db.add(product)
db.commit()
db.refresh(product)
logger.info(f"Added product {product.id} to vendor {vendor_id} catalog")
return product
except (ProductAlreadyExistsException, ValidationException):
db.rollback()
raise
except Exception as e:
db.rollback()
logger.error(f"Error creating product: {str(e)}")
raise ValidationException("Failed to create product")
def update_product(
self,
db: Session,
vendor_id: int,
product_id: int,
product_update: ProductUpdate,
) -> Product:
"""
Update product in vendor catalog.
Args:
db: Database session
vendor_id: Vendor ID
product_id: Product ID
product_update: Update data
Returns:
Updated Product object
"""
try:
product = self.get_product(db, vendor_id, product_id)
# Update fields
update_data = product_update.model_dump(exclude_unset=True)
for key, value in update_data.items():
setattr(product, key, value)
product.updated_at = datetime.now(UTC)
db.commit()
db.refresh(product)
logger.info(f"Updated product {product_id} in vendor {vendor_id} catalog")
return product
except ProductNotFoundException:
db.rollback()
raise
except Exception as e:
db.rollback()
logger.error(f"Error updating product: {str(e)}")
raise ValidationException("Failed to update product")
def delete_product(self, db: Session, vendor_id: int, product_id: int) -> bool:
"""
Remove product from vendor catalog.
Args:
db: Database session
vendor_id: Vendor ID
product_id: Product ID
Returns:
True if deleted
"""
try:
product = self.get_product(db, vendor_id, product_id)
db.delete(product)
db.commit()
logger.info(f"Deleted product {product_id} from vendor {vendor_id} catalog")
return True
except ProductNotFoundException:
raise
except Exception as e:
db.rollback()
logger.error(f"Error deleting product: {str(e)}")
raise ValidationException("Failed to delete product")
def get_vendor_products(
self,
db: Session,
vendor_id: int,
skip: int = 0,
limit: int = 100,
is_active: bool | None = None,
is_featured: bool | None = None,
) -> tuple[list[Product], int]:
"""
Get products in vendor catalog with filtering.
Args:
db: Database session
vendor_id: Vendor ID
skip: Pagination offset
limit: Pagination limit
is_active: Filter by active status
is_featured: Filter by featured status
Returns:
Tuple of (products, total_count)
"""
try:
query = db.query(Product).filter(Product.vendor_id == vendor_id)
if is_active is not None:
query = query.filter(Product.is_active == is_active)
if is_featured is not None:
query = query.filter(Product.is_featured == is_featured)
total = query.count()
products = query.offset(skip).limit(limit).all()
return products, total
except Exception as e:
logger.error(f"Error getting vendor products: {str(e)}")
raise ValidationException("Failed to retrieve products")
# Create service instance
product_service = ProductService()