"""
Product Pydantic Schemas
Validation schemas for WooCommerce products and related entities.
"""
from typing import Any
from pydantic import BaseModel, ConfigDict, Field, field_validator
class ProductBase(BaseModel):
"""Base product schema"""
name: str | None = Field(None, description="Product name")
type: str | None = Field("simple", description="Product type")
status: str | None = Field("draft", description="Product status")
featured: bool | None = Field(False, description="Featured product flag")
catalog_visibility: str | None = Field("visible", description="Catalog visibility")
description: str | None = Field(None, description="Product description (HTML)")
short_description: str | None = Field(None, description="Short description (HTML)")
sku: str | None = Field(None, description="Stock Keeping Unit")
regular_price: str | None = Field(None, description="Regular price")
sale_price: str | None = Field(None, description="Sale price")
manage_stock: bool | None = Field(False, description="Manage stock flag")
stock_quantity: int | None = Field(None, description="Stock quantity")
stock_status: str | None = Field("instock", description="Stock status")
weight: str | None = Field(None, description="Product weight")
length: str | None = Field(None, description="Product length")
width: str | None = Field(None, description="Product width")
height: str | None = Field(None, description="Product height")
categories: list[dict[str, Any]] | None = Field(None, description="Product categories")
tags: list[dict[str, Any]] | None = Field(None, description="Product tags")
images: list[dict[str, Any]] | None = Field(None, description="Product images")
attributes: list[dict[str, Any]] | None = Field(None, description="Product attributes")
model_config = ConfigDict(extra="allow")
@classmethod
@field_validator("type")
def validate_type(cls, v):
if v is not None:
allowed = ["simple", "grouped", "external", "variable", "variation"]
if v not in allowed:
raise ValueError(f"Type must be one of: {', '.join(allowed)}")
return v
@classmethod
@field_validator("status")
def validate_status(cls, v):
if v is not None:
allowed = ["draft", "pending", "private", "publish"]
if v not in allowed:
raise ValueError(f"Status must be one of: {', '.join(allowed)}")
return v
@classmethod
@field_validator("catalog_visibility")
def validate_visibility(cls, v):
if v is not None:
allowed = ["visible", "catalog", "search", "hidden"]
if v not in allowed:
raise ValueError(f"Visibility must be one of: {', '.join(allowed)}")
return v
@classmethod
@field_validator("stock_status")
def validate_stock_status(cls, v):
if v is not None:
allowed = ["instock", "outofstock", "onbackorder"]
if v not in allowed:
raise ValueError(f"Stock status must be one of: {', '.join(allowed)}")
return v
class ProductCreate(ProductBase):
"""Schema for creating a new product"""
name: str = Field(..., min_length=1, description="Product name (required)")
type: str = Field("simple", description="Product type")
class ProductUpdate(ProductBase):
"""Schema for updating an existing product"""
# All fields optional for updates
pass
class ProductResponse(BaseModel):
"""Schema for product response data"""
model_config = ConfigDict(extra="allow")
id: int
name: str
slug: str
type: str
status: str
featured: bool
regular_price: str
sale_price: str
price: str
stock_status: str
permalink: str
class ProductCategory(BaseModel):
"""Schema for product category"""
model_config = ConfigDict(extra="allow")
name: str = Field(..., description="Category name")
slug: str | None = Field(None, description="Category slug")
parent: int | None = Field(None, description="Parent category ID")
description: str | None = Field(None, description="Category description")
display: str | None = Field("default", description="Display type")
image: dict[str, Any] | None = Field(None, description="Category image")
class ProductVariation(BaseModel):
"""Schema for product variation"""
model_config = ConfigDict(extra="allow")
regular_price: str | None = Field(None, description="Regular price")
sale_price: str | None = Field(None, description="Sale price")
description: str | None = Field(None, description="Variation description")
sku: str | None = Field(None, description="Stock Keeping Unit")
manage_stock: bool | None = Field(False, description="Manage stock flag")
stock_quantity: int | None = Field(None, description="Stock quantity")
stock_status: str | None = Field("instock", description="Stock status")
weight: str | None = Field(None, description="Variation weight")
attributes: list[dict[str, Any]] | None = Field(None, description="Variation attributes")
image: dict[str, Any] | None = Field(None, description="Variation image")
class ProductAttribute(BaseModel):
"""Schema for product attribute"""
model_config = ConfigDict(extra="allow")
name: str = Field(..., description="Attribute name")
slug: str | None = Field(None, description="Attribute slug")
type: str | None = Field("select", description="Attribute type")
order_by: str | None = Field("menu_order", description="Sort order")
has_archives: bool | None = Field(False, description="Enable archives")