- Fix Python formatting (sync no longer strips blank lines from .py files) - Remove test_community_build.py (tests private sync module) - Fix ruff warnings in test files - Add CODE_OF_CONDUCT.md - Add .github/PULL_REQUEST_TEMPLATE.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
148 lines
5.6 KiB
Python
148 lines
5.6 KiB
Python
"""
|
|
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")
|