Files
orion/models/schema/vendor_product.py
Samir Boulahtit 508e121a0e refactor: product independence - remove inheritance pattern
Change Product/ProductTranslation from "override/inheritance" pattern
(NULL = inherit from marketplace) to "independent copy" pattern
(all fields populated at creation).

Key changes:
- Remove OVERRIDABLE_FIELDS, effective_* properties, reset_* methods
- Rename get_override_info() → get_source_comparison_info()
- Update copy_to_vendor_catalog() to copy ALL fields + translations
- Replace effective_* with direct field access in services
- Remove *_overridden fields from schema, keep *_source for comparison
- Add migration to populate NULL fields from marketplace products

The marketplace_product_id FK is kept for "view original source" feature.
Rollback tag: v1.0.0-pre-product-independence

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 23:41:20 +01:00

145 lines
4.0 KiB
Python

# models/schema/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
vendor_sku: str | None = None
title: str | None = None
brand: str | None = None
price: float | None = None
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
vendor_sku: str | None = None
# 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
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
# Timestamps
created_at: str | None = None
updated_at: str | None = None
class RemoveProductResponse(BaseModel):
"""Response from product removal."""
message: str