200 lines
6.3 KiB
Python
200 lines
6.3 KiB
Python
"""
|
|
Catalog and product management for POD services.
|
|
"""
|
|
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
import yaml
|
|
from rich.console import Console
|
|
from rich.table import Table
|
|
|
|
console = Console()
|
|
|
|
|
|
def get_project_root() -> Path:
|
|
"""Find the project root."""
|
|
current = Path.cwd()
|
|
while current != current.parent:
|
|
if (current / "designs").is_dir():
|
|
return current
|
|
current = current.parent
|
|
return Path.cwd()
|
|
|
|
|
|
DESIGNS_DIR = get_project_root() / "designs"
|
|
CONFIG_DIR = get_project_root() / "config"
|
|
|
|
|
|
def create_product(path: str, provider: str, sandbox: bool = False) -> None:
|
|
"""Create a product on a POD service."""
|
|
design_dir = DESIGNS_DIR / path
|
|
|
|
if not design_dir.exists():
|
|
console.print(f"[red]Error: Design not found at {design_dir}[/red]")
|
|
raise SystemExit(1)
|
|
|
|
metadata_path = design_dir / "metadata.yaml"
|
|
if not metadata_path.exists():
|
|
console.print("[red]Error: metadata.yaml not found[/red]")
|
|
raise SystemExit(1)
|
|
|
|
with open(metadata_path) as f:
|
|
metadata = yaml.safe_load(f)
|
|
|
|
products = metadata.get("products", [])
|
|
matching_products = [p for p in products if p.get("provider") == provider]
|
|
|
|
if not matching_products:
|
|
console.print(f"[yellow]No products configured for provider '{provider}'[/yellow]")
|
|
console.print("Add products to metadata.yaml first.")
|
|
raise SystemExit(1)
|
|
|
|
mode = "SANDBOX" if sandbox else "PRODUCTION"
|
|
console.print(f"\n[bold]Creating products on {provider} ({mode})[/bold]\n")
|
|
|
|
for product in matching_products:
|
|
product_type = product.get("type", "unknown")
|
|
sku = product.get("sku", "N/A")
|
|
price = product.get("retail_price", 0)
|
|
|
|
console.print(f" Product: {product_type}")
|
|
console.print(f" SKU: {sku}")
|
|
console.print(f" Price: ${price:.2f}")
|
|
|
|
if provider == "printful":
|
|
_create_printful_product(design_dir, metadata, product, sandbox)
|
|
elif provider == "prodigi":
|
|
_create_prodigi_product(design_dir, metadata, product, sandbox)
|
|
else:
|
|
console.print(f"[red] Unknown provider: {provider}[/red]")
|
|
|
|
console.print()
|
|
|
|
|
|
def _create_printful_product(
|
|
design_dir: Path,
|
|
metadata: dict,
|
|
product: dict,
|
|
sandbox: bool
|
|
) -> None:
|
|
"""Create product on Printful."""
|
|
console.print("[yellow] → Printful API integration not yet implemented[/yellow]")
|
|
console.print("[dim] Would create product with Printful API[/dim]")
|
|
# TODO: Implement Printful API call
|
|
# 1. Upload design file to Printful
|
|
# 2. Create sync product
|
|
# 3. Add sync variants
|
|
# 4. Store Printful product ID in metadata
|
|
|
|
|
|
def _create_prodigi_product(
|
|
design_dir: Path,
|
|
metadata: dict,
|
|
product: dict,
|
|
sandbox: bool
|
|
) -> None:
|
|
"""Create product on Prodigi."""
|
|
console.print("[yellow] → Prodigi API integration not yet implemented[/yellow]")
|
|
console.print("[dim] Would create product with Prodigi API[/dim]")
|
|
# TODO: Implement Prodigi API call
|
|
# 1. Upload design file to Prodigi
|
|
# 2. Create product template
|
|
# 3. Store Prodigi template ID in metadata
|
|
|
|
|
|
def push_product(path: str, provider: Optional[str] = None) -> None:
|
|
"""Push design updates to POD product."""
|
|
design_dir = DESIGNS_DIR / path
|
|
|
|
if not design_dir.exists():
|
|
console.print(f"[red]Error: Design not found at {design_dir}[/red]")
|
|
raise SystemExit(1)
|
|
|
|
metadata_path = design_dir / "metadata.yaml"
|
|
if not metadata_path.exists():
|
|
console.print("[red]Error: metadata.yaml not found[/red]")
|
|
raise SystemExit(1)
|
|
|
|
with open(metadata_path) as f:
|
|
metadata = yaml.safe_load(f)
|
|
|
|
products = metadata.get("products", [])
|
|
|
|
if provider:
|
|
products = [p for p in products if p.get("provider") == provider]
|
|
|
|
if not products:
|
|
console.print("[yellow]No products to push[/yellow]")
|
|
raise SystemExit(1)
|
|
|
|
console.print(f"\n[bold]Pushing updates for: {metadata.get('name', path)}[/bold]\n")
|
|
|
|
for product in products:
|
|
prod_provider = product.get("provider", "unknown")
|
|
product_type = product.get("type", "unknown")
|
|
|
|
console.print(f" Pushing {product_type} to {prod_provider}...")
|
|
console.print("[yellow] → API integration not yet implemented[/yellow]")
|
|
# TODO: Implement push logic
|
|
# 1. Check if product exists on provider
|
|
# 2. Upload updated design file
|
|
# 3. Sync any metadata changes
|
|
|
|
|
|
def list_products(provider: Optional[str] = None) -> None:
|
|
"""List all products across designs."""
|
|
table = Table(title="🍄 Mycopunk Products")
|
|
table.add_column("Design", style="cyan")
|
|
table.add_column("Type", style="green")
|
|
table.add_column("Provider", style="yellow")
|
|
table.add_column("SKU", style="blue")
|
|
table.add_column("Price", style="magenta", justify="right")
|
|
table.add_column("Status", style="dim")
|
|
|
|
products_found = 0
|
|
|
|
for category_dir in DESIGNS_DIR.iterdir():
|
|
if not category_dir.is_dir():
|
|
continue
|
|
|
|
for design_dir in category_dir.iterdir():
|
|
if not design_dir.is_dir():
|
|
continue
|
|
|
|
metadata_path = design_dir / "metadata.yaml"
|
|
if not metadata_path.exists():
|
|
continue
|
|
|
|
try:
|
|
with open(metadata_path) as f:
|
|
metadata = yaml.safe_load(f)
|
|
except Exception:
|
|
continue
|
|
|
|
design_path = f"{category_dir.name}/{design_dir.name}"
|
|
design_status = metadata.get("status", "unknown")
|
|
products = metadata.get("products", [])
|
|
|
|
for product in products:
|
|
prod_provider = product.get("provider", "unknown")
|
|
|
|
if provider and prod_provider != provider:
|
|
continue
|
|
|
|
products_found += 1
|
|
table.add_row(
|
|
design_path,
|
|
product.get("type", "unknown"),
|
|
prod_provider,
|
|
product.get("sku", "N/A"),
|
|
f"${product.get('retail_price', 0):.2f}",
|
|
design_status,
|
|
)
|
|
|
|
if products_found == 0:
|
|
console.print("[yellow]No products found.[/yellow]")
|
|
else:
|
|
console.print(table)
|
|
console.print(f"\n[dim]Total: {products_found} product(s)[/dim]")
|