53 lines
1.7 KiB
Python
53 lines
1.7 KiB
Python
"""Pluggable product fetch / stock-sync scripts for the admin CMS.
|
|
|
|
Each fetcher module must expose:
|
|
NAME: str
|
|
DESCRIPTION: str
|
|
fetch_products(config: dict) -> list[dict]
|
|
sync_stocks(config: dict, products: list[dict]) -> list[dict]
|
|
|
|
Product dict keys (camelCase or snake_case accepted by importer):
|
|
id, slug, name, nameFa/name_fa, price, compareAtPrice/compare_at_price,
|
|
stock, heroImage/hero_image, category, categoryFa/category_fa,
|
|
description, sku, externalId/external_id, colorVariants/color_variants,
|
|
source
|
|
|
|
Each colorVariants item may include:
|
|
id, slug, name, shade, colorHex, price, compareAtPrice, stock,
|
|
heroImage, sku, externalId, images[]
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import pkgutil
|
|
from pathlib import Path
|
|
|
|
_PACKAGE = Path(__file__).resolve().parent
|
|
|
|
|
|
def list_fetchers():
|
|
items = []
|
|
for mod in pkgutil.iter_modules([str(_PACKAGE)]):
|
|
if mod.name.startswith("_"):
|
|
continue
|
|
module = importlib.import_module(f"fetchers.{mod.name}")
|
|
if not hasattr(module, "NAME"):
|
|
continue
|
|
items.append(
|
|
{
|
|
"id": mod.name,
|
|
"name": getattr(module, "NAME"),
|
|
"description": getattr(module, "DESCRIPTION", ""),
|
|
"supports_fetch": callable(getattr(module, "fetch_products", None)),
|
|
"supports_sync": callable(getattr(module, "sync_stocks", None)),
|
|
}
|
|
)
|
|
return sorted(items, key=lambda x: x["id"])
|
|
|
|
|
|
def get_fetcher(fetcher_id: str):
|
|
if not fetcher_id or "/" in fetcher_id or ".." in fetcher_id:
|
|
raise ValueError("invalid fetcher id")
|
|
return importlib.import_module(f"fetchers.{fetcher_id}")
|