refactor: clean up legacy models and migrate remaining schemas

Delete empty stub files from models/database/:
- audit.py, backup.py, configuration.py, monitoring.py
- notification.py, payment.py, search.py, task.py

Delete re-export files:
- models/database/subscription.py → app.modules.billing.models
- models/database/architecture_scan.py → app.modules.dev_tools.models
- models/database/test_run.py → app.modules.dev_tools.models
- models/schema/subscription.py → app.modules.billing.schemas
- models/schema/marketplace.py (empty)
- models/schema/monitoring.py (empty)

Migrate schemas to canonical module locations:
- billing.py → app/modules/billing/schemas/
- vendor_product.py → app/modules/catalog/schemas/
- homepage_sections.py → app/modules/cms/schemas/

Keep as CORE (framework-level, used everywhere):
- models/schema/: admin, auth, base, company, email, image, media, team, vendor*
- models/database/: admin*, base, company, email, feature, media, platform*, user, vendor*

Update 30+ files to use canonical import locations.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-30 18:45:46 +01:00
parent 1ef50893a1
commit b9f08b853f
49 changed files with 152 additions and 220 deletions

View File

@@ -15,6 +15,23 @@ from app.modules.catalog.schemas.product import (
ProductDeleteResponse,
ProductToggleResponse,
)
from app.modules.catalog.schemas.vendor_product import (
# List/Detail schemas
VendorProductListItem,
VendorProductListResponse,
VendorProductStats,
VendorProductDetail,
# Catalog vendor schemas
CatalogVendor,
CatalogVendorsResponse,
# CRUD schemas
TranslationUpdate,
VendorProductCreate,
VendorDirectProductCreate,
VendorProductUpdate,
VendorProductCreateResponse,
RemoveProductResponse,
)
__all__ = [
# Catalog browsing schemas (storefront)
@@ -29,4 +46,17 @@ __all__ = [
"ProductListResponse",
"ProductDeleteResponse",
"ProductToggleResponse",
# Vendor Product schemas (admin)
"VendorProductListItem",
"VendorProductListResponse",
"VendorProductStats",
"VendorProductDetail",
"CatalogVendor",
"CatalogVendorsResponse",
"TranslationUpdate",
"VendorProductCreate",
"VendorDirectProductCreate",
"VendorProductUpdate",
"VendorProductCreateResponse",
"RemoveProductResponse",
]

View File

@@ -0,0 +1,247 @@
# app/modules/catalog/schemas/vendor_product.py
"""
Pydantic schemas for vendor product catalog operations.
Used by admin vendor product endpoints for:
- Product listing and filtering
- Product statistics
- Product detail views
- Catalog vendor listings
"""
from pydantic import BaseModel, ConfigDict
class VendorProductListItem(BaseModel):
"""Product item for vendor catalog list view."""
model_config = ConfigDict(from_attributes=True)
id: int
vendor_id: int
vendor_name: str | None = None
vendor_code: str | None = None
marketplace_product_id: int | None = None
vendor_sku: str | None = None
title: str | None = None
brand: str | None = None
price: float | None = None
currency: str | None = None
effective_price: float | None = None
effective_currency: str | None = None
is_active: bool | None = None
is_featured: bool | None = None
is_digital: bool | None = None
image_url: str | None = None
source_marketplace: str | None = None
source_vendor: str | None = None
created_at: str | None = None
updated_at: str | None = None
class VendorProductListResponse(BaseModel):
"""Paginated vendor product list response."""
products: list[VendorProductListItem]
total: int
skip: int
limit: int
class VendorProductStats(BaseModel):
"""Vendor product statistics."""
total: int
active: int
inactive: int
featured: int
digital: int
physical: int
by_vendor: dict[str, int]
class CatalogVendor(BaseModel):
"""Vendor with products in catalog."""
id: int
name: str
vendor_code: str
class CatalogVendorsResponse(BaseModel):
"""Response for catalog vendors list."""
vendors: list[CatalogVendor]
class VendorProductDetail(BaseModel):
"""Detailed vendor product information.
Products are independent entities - all fields are populated at creation.
Source values are kept for "view original source" comparison only.
"""
id: int
vendor_id: int
vendor_name: str | None = None
vendor_code: str | None = None
marketplace_product_id: int | None = None # Optional for direct product creation
vendor_sku: str | None = None
# Product identifiers
gtin: str | None = None
gtin_type: str | None = None # ean13, ean8, upc, isbn, etc.
# Product fields with source comparison
price: float | None = None
price_cents: int | None = None
price_source: float | None = None # For "view original source" feature
sale_price: float | None = None
sale_price_cents: int | None = None
sale_price_source: float | None = None
currency: str | None = None
currency_source: str | None = None
brand: str | None = None
brand_source: str | None = None
condition: str | None = None
condition_source: str | None = None
availability: str | None = None
availability_source: str | None = None
primary_image_url: str | None = None
primary_image_url_source: str | None = None
additional_images: list[str] | None = None
is_digital: bool | None = None
product_type: str | None = None
# Vendor-specific fields
is_featured: bool | None = None
is_active: bool | None = None
display_order: int | None = None
min_quantity: int | None = None
max_quantity: int | None = None
# Supplier tracking
supplier: str | None = None
supplier_product_id: str | None = None
cost: float | None = None # What vendor pays to acquire product
margin_percent: float | None = None
# Tax/profit info
tax_rate_percent: int | None = None
net_price: float | None = None
vat_amount: float | None = None
profit: float | None = None
profit_margin_percent: float | None = None
# Digital fulfillment
download_url: str | None = None
license_type: str | None = None
fulfillment_email_template: str | None = None
# Source info
source_marketplace: str | None = None
source_vendor: str | None = None
source_gtin: str | None = None
source_sku: str | None = None
# Translations
marketplace_translations: dict | None = None
vendor_translations: dict | None = None
# Convenience fields for UI display
title: str | None = None
description: str | None = None
image_url: str | None = None # Alias for primary_image_url
# Timestamps
created_at: str | None = None
updated_at: str | None = None
class RemoveProductResponse(BaseModel):
"""Response from product removal."""
message: str
class TranslationUpdate(BaseModel):
"""Translation data for a single language."""
title: str | None = None
description: str | None = None
class VendorProductCreate(BaseModel):
"""Schema for creating a vendor product (admin use - includes vendor_id)."""
vendor_id: int
# Translations by language code (en, fr, de, lu)
translations: dict[str, TranslationUpdate] | None = None
# Product identifiers
brand: str | None = None
vendor_sku: str | None = None
gtin: str | None = None
gtin_type: str | None = None # ean13, ean8, upc, isbn
# Pricing
price: float | None = None
sale_price: float | None = None
currency: str = "EUR"
tax_rate_percent: int | None = 17 # Default Luxembourg VAT
availability: str | None = None
# Images
primary_image_url: str | None = None
additional_images: list[str] | None = None
# Status
is_active: bool = True
is_featured: bool = False
is_digital: bool = False
class VendorDirectProductCreate(BaseModel):
"""Schema for vendor direct product creation (vendor_id from JWT token)."""
title: str
brand: str | None = None
vendor_sku: str | None = None
gtin: str | None = None
price: float | None = None
currency: str = "EUR"
availability: str | None = None
is_active: bool = True
is_featured: bool = False
description: str | None = None
class VendorProductUpdate(BaseModel):
"""Schema for updating a vendor product."""
# Translations by language code (en, fr, de, lu)
translations: dict[str, TranslationUpdate] | None = None
# Product identifiers
brand: str | None = None
vendor_sku: str | None = None
gtin: str | None = None
gtin_type: str | None = None # ean13, ean8, upc, isbn, etc.
# Pricing
price: float | None = None # Price incl. VAT in euros
sale_price: float | None = None # Optional sale price
currency: str | None = None
tax_rate_percent: int | None = None # 3, 8, 14, 17
availability: str | None = None # in_stock, out_of_stock, preorder, backorder
# Status
is_digital: bool | None = None
is_active: bool | None = None
is_featured: bool | None = None
# Images
primary_image_url: str | None = None
additional_images: list[str] | None = None
# Optional supplier info
supplier: str | None = None
cost: float | None = None # Cost in euros
class VendorProductCreateResponse(BaseModel):
"""Response from product creation."""
id: int
message: str