# models/schema/marketplace_product.py """Pydantic schemas for MarketplaceProduct API validation. Note: title and description are stored in MarketplaceProductTranslation table, but we keep them in the API schemas for convenience. The service layer handles creating/updating translations separately. """ from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from models.schema.inventory import ProductInventorySummary class MarketplaceProductTranslationSchema(BaseModel): """Schema for product translation.""" model_config = ConfigDict(from_attributes=True) language: str title: str description: str | None = None short_description: str | None = None meta_title: str | None = None meta_description: str | None = None url_slug: str | None = None class MarketplaceProductBase(BaseModel): """Base schema for marketplace products.""" marketplace_product_id: str | None = None # Localized fields (passed to translations) title: str | None = None description: str | None = None # Links and media link: str | None = None image_link: str | None = None additional_image_link: str | None = None # Status availability: str | None = None is_active: bool | None = None # Pricing price: str | None = None sale_price: str | None = None currency: str | None = None # Product identifiers brand: str | None = None gtin: str | None = None mpn: str | None = None sku: str | None = None # Product attributes condition: str | None = None adult: str | None = None multipack: int | None = None is_bundle: str | None = None age_group: str | None = None color: str | None = None gender: str | None = None material: str | None = None pattern: str | None = None size: str | None = None size_type: str | None = None size_system: str | None = None item_group_id: str | None = None # Categories google_product_category: str | None = None product_type_raw: str | None = ( None # Original feed value (renamed from product_type) ) category_path: str | None = None # Custom labels custom_label_0: str | None = None custom_label_1: str | None = None custom_label_2: str | None = None custom_label_3: str | None = None custom_label_4: str | None = None # Unit pricing unit_pricing_measure: str | None = None unit_pricing_base_measure: str | None = None identifier_exists: str | None = None shipping: str | None = None # Source tracking marketplace: str | None = None vendor_name: str | None = None source_url: str | None = None # Product type classification product_type_enum: str | None = ( None # 'physical', 'digital', 'service', 'subscription' ) is_digital: bool | None = None # Digital product fields digital_delivery_method: str | None = None platform: str | None = None license_type: str | None = None # Physical product fields weight: float | None = None weight_unit: str | None = None class MarketplaceProductCreate(MarketplaceProductBase): """Schema for creating a marketplace product.""" marketplace_product_id: str = Field( ..., description="Unique product identifier from marketplace" ) # Title is required for API creation (will be stored in translations) title: str = Field(..., description="Product title") class MarketplaceProductUpdate(MarketplaceProductBase): """Schema for updating a marketplace product. All fields are optional - only provided fields will be updated. """ class MarketplaceProductResponse(BaseModel): """Schema for marketplace product API response.""" model_config = ConfigDict(from_attributes=True) id: int marketplace_product_id: str # These will be populated from translations title: str | None = None description: str | None = None # Links and media link: str | None = None image_link: str | None = None additional_image_link: str | None = None # Status availability: str | None = None is_active: bool | None = None # Pricing price: str | None = None price_numeric: float | None = None sale_price: str | None = None sale_price_numeric: float | None = None currency: str | None = None # Product identifiers brand: str | None = None gtin: str | None = None mpn: str | None = None sku: str | None = None # Product attributes condition: str | None = None color: str | None = None size: str | None = None # Categories google_product_category: str | None = None product_type_raw: str | None = None category_path: str | None = None # Source tracking marketplace: str | None = None vendor_name: str | None = None # Product type product_type_enum: str | None = None is_digital: bool | None = None platform: str | None = None # Timestamps created_at: datetime updated_at: datetime # Translations (optional - included when requested) translations: list[MarketplaceProductTranslationSchema] | None = None class MarketplaceProductListResponse(BaseModel): """Schema for paginated product list response.""" products: list[MarketplaceProductResponse] total: int skip: int limit: int class MarketplaceProductDetailResponse(BaseModel): """Schema for detailed product response with inventory.""" product: MarketplaceProductResponse inventory_info: ProductInventorySummary | None = None translations: list[MarketplaceProductTranslationSchema] | None = None class MarketplaceImportRequest(BaseModel): """Schema for marketplace import request.""" url: str = Field(..., description="URL to CSV file") marketplace: str = Field(default="Letzshop", description="Marketplace name") vendor_name: str | None = Field(default=None, description="Vendor name") language: str = Field(default="en", description="Language code for translations") batch_size: int = Field(default=100, ge=1, le=1000, description="Batch size") class MarketplaceImportResponse(BaseModel): """Schema for marketplace import response.""" job_id: int status: str message: str