Application fully migrated to modular approach

This commit is contained in:
2025-09-13 21:30:40 +02:00
parent c7d6b33cd5
commit b9fe91ab88
38 changed files with 509 additions and 265 deletions

View File

@@ -159,6 +159,7 @@ class AdminService:
job_id=job.id,
status=job.status,
marketplace=job.marketplace,
shop_id=job.shop.id,
shop_name=job.shop_name,
imported=job.imported_count or 0,
updated=job.updated_count or 0,

View File

@@ -1,3 +1,4 @@
from sqlalchemy import func
from sqlalchemy.orm import Session
from models.database_models import MarketplaceImportJob, Shop, User
from models.api_models import MarketplaceImportRequest, MarketplaceImportJobResponse
@@ -14,7 +15,11 @@ class MarketplaceService:
def validate_shop_access(self, db: Session, shop_code: str, user: User) -> Shop:
"""Validate that the shop exists and user has access to it"""
shop = db.query(Shop).filter(Shop.shop_code == shop_code).first()
# Explicit type hint to help type checker shop: Optional[Shop]
# Use case-insensitive query to handle both uppercase and lowercase codes
shop: Optional[Shop] = db.query(Shop).filter(
func.upper(Shop.shop_code) == shop_code.upper()
).first()
if not shop:
raise ValueError("Shop not found")

View File

@@ -1,4 +1,5 @@
from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from models.database_models import Product, Stock
from models.api_models import ProductCreate, ProductUpdate, StockLocationResponse, StockSummaryResponse
from utils.data_processing import GTINProcessor, PriceProcessor
@@ -16,31 +17,41 @@ class ProductService:
def create_product(self, db: Session, product_data: ProductCreate) -> Product:
"""Create a new product with validation"""
# Process and validate GTIN if provided
if product_data.gtin:
normalized_gtin = self.gtin_processor.normalize(product_data.gtin)
if not normalized_gtin:
raise ValueError("Invalid GTIN format")
product_data.gtin = normalized_gtin
try:
# Process and validate GTIN if provided
if product_data.gtin:
normalized_gtin = self.gtin_processor.normalize(product_data.gtin)
if not normalized_gtin:
raise ValueError("Invalid GTIN format")
product_data.gtin = normalized_gtin
# Process price if provided
if product_data.price:
parsed_price, currency = self.price_processor.parse_price_currency(product_data.price)
if parsed_price:
product_data.price = parsed_price
product_data.currency = currency
# Process price if provided
if product_data.price:
parsed_price, currency = self.price_processor.parse_price_currency(product_data.price)
if parsed_price:
product_data.price = parsed_price
product_data.currency = currency
# Set default marketplace if not provided
if not product_data.marketplace:
product_data.marketplace = "Letzshop"
# Set default marketplace if not provided
if not product_data.marketplace:
product_data.marketplace = "Letzshop"
db_product = Product(**product_data.dict())
db.add(db_product)
db.commit()
db.refresh(db_product)
db_product = Product(**product_data.model_dump())
db.add(db_product)
db.commit()
db.refresh(db_product)
logger.info(f"Created product {db_product.product_id}")
return db_product
logger.info(f"Created product {db_product.product_id}")
return db_product
except IntegrityError as e:
db.rollback()
logger.error(f"Database integrity error: {str(e)}")
raise ValueError("Product with this ID already exists")
except Exception as e:
db.rollback()
logger.error(f"Error creating product: {str(e)}")
raise
def get_product_by_id(self, db: Session, product_id: str) -> Optional[Product]:
"""Get a product by its ID"""
@@ -94,7 +105,7 @@ class ProductService:
raise ValueError("Product not found")
# Update fields
update_data = product_update.dict(exclude_unset=True)
update_data = product_update.model_dump(exclude_unset=True)
# Validate GTIN if being updated
if "gtin" in update_data and update_data["gtin"]:

View File

@@ -1,3 +1,4 @@
from sqlalchemy import func
from sqlalchemy.orm import Session
from fastapi import HTTPException
from datetime import datetime
@@ -28,17 +29,26 @@ class ShopService:
Raises:
HTTPException: If shop code already exists
"""
# Check if shop code already exists
existing_shop = db.query(Shop).filter(Shop.shop_code == shop_data.shop_code).first()
# Normalize shop code to uppercase
normalized_shop_code = shop_data.shop_code.upper()
# Check if shop code already exists (case-insensitive check against existing data)
existing_shop = db.query(Shop).filter(
func.upper(Shop.shop_code) == normalized_shop_code
).first()
if existing_shop:
raise HTTPException(status_code=400, detail="Shop code already exists")
# Create shop
# Create shop with uppercase code
shop_dict = shop_data.model_dump() # Fixed deprecated .dict() method
shop_dict['shop_code'] = normalized_shop_code # Store as uppercase
new_shop = Shop(
**shop_data.dict(),
**shop_dict,
owner_id=current_user.id,
is_active=True,
is_verified=(current_user.role == "admin") # Auto-verify if admin creates shop
is_verified=(current_user.role == "admin")
)
db.add(new_shop)
@@ -106,7 +116,8 @@ class ShopService:
Raises:
HTTPException: If shop not found or access denied
"""
shop = db.query(Shop).filter(Shop.shop_code == shop_code.upper()).first()
# Explicit type hint to help type checker shop: Optional[Shop]
shop: Optional[Shop] = db.query(Shop).filter(func.upper(Shop.shop_code) == shop_code.upper()).first()
if not shop:
raise HTTPException(status_code=404, detail="Shop not found")
@@ -155,7 +166,7 @@ class ShopService:
new_shop_product = ShopProduct(
shop_id=shop.id,
product_id=product.id,
**shop_product.dict(exclude={'product_id'})
**shop_product.model_dump(exclude={'product_id'})
)
db.add(new_shop_product)