Files
ecm_sync_system/sync_state_machine/domain/supplier/api_handler.py
T
strepsiades 4a9c444b10 first commit
2026-03-09 16:31:42 +08:00

146 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Supplier API Handler (只读)
职责:
- 加载供应商列表
- 不支持创建/更新/删除
"""
from typing import List, Dict, Any
from ...datasource.api.handler import BaseApiHandler
from ...datasource.task_result import TaskResult
from ...common.sync_node import SyncNode
from .sync_node import SupplierSyncNode
from schemas.supplier.supplier import SupplierDetailResponse
class SupplierApiHandler(BaseApiHandler):
"""供应商 API Handler (只读)"""
def __init__(self, load_mode: str = "api", max_total: int | None = None):
super().__init__()
self._node_type = "supplier"
self._node_class = SupplierSyncNode
self._schema = SupplierDetailResponse
self._load_mode = load_mode
self._max_total = max_total
async def load(self) -> List[SyncNode]:
"""加载供应商列表(支持分页)"""
try:
if self._load_mode == "persisted_only":
existing_count = 0
if self._collection is not None:
existing_count = len(self._collection.filter(node_type=self.node_type))
print(f"️ Supplier load skipped (persisted_only). Existing={existing_count}")
return []
nodes = []
page = 1
page_size = 10000
while True:
# 获取一页数据
suppliers, total = await api_get_supplier_list(
self.api_client,
page=page,
page_size=page_size
)
# 没有数据了,退出循环
if not suppliers:
break
# 转换为节点
for supplier_model in suppliers:
supplier_data = supplier_model.model_dump()
nodes.append(self._create_node(supplier_data))
if self._max_total is not None and len(nodes) >= self._max_total:
return nodes
# 检查是否还有下一页
if total > 0 and page * page_size >= total:
break
# 如果没有total字段,且items数量小于page_size,说明是最后一页
if total == 0 and len(suppliers) < page_size:
break
page += 1
return nodes
except Exception as e:
print(f"❌ Failed to load suppliers: {e}")
return []
async def create_all(self, nodes: List[SyncNode]) -> List[TaskResult]:
"""不支持创建"""
return [
TaskResult.failed(node_id=node.node_id, error="Supplier creation not supported")
for node in nodes
]
async def update_all(self, nodes: List[SyncNode]) -> List[TaskResult]:
"""不支持更新"""
return [
TaskResult.failed(node_id=node.node_id, error="Supplier update not supported")
for node in nodes
]
async def delete_all(self, nodes: List[SyncNode]) -> List[TaskResult]:
"""不支持删除"""
return [
TaskResult.failed(node_id=node.node_id, error="Supplier deletion not supported")
for node in nodes
]
async def poll_tasks(self, task_ids: List[str]) -> Dict[str, TaskResult]:
"""轮询异步任务状态(占位)"""
return await super().poll_tasks(task_ids)
def _create_node(self, data: Dict[str, Any]) -> SyncNode:
return self._create_basic_node(data, depend_ids=[])
# ========== 静态 API 函数 ==========
async def api_get_supplier_list(client, page: int = 1, page_size: int = 100) -> tuple[List[SupplierDetailResponse], int]:
"""
获取供应商列表 GET /supplier/list
Args:
client: API客户端
page: 页码,从1开始
page_size: 每页大小
Returns:
tuple[List[SupplierDetailResponse], int]: (验证过的供应商列表, 总数)
"""
from pydantic import ValidationError
response = await client.request(
method="GET",
endpoint="/supplier/list",
params={"page": page, "page_size": page_size}
)
if response.get("code") != 200:
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
# 注意:supplier返回格式可能是 {code: 200, list: [...]} 或 {code: 200, data: {list: [...]}}
data = response.get("data", {})
items = data.get("list", []) if data else response.get("list", [])
total = data.get("total", 0) if data else response.get("total", 0)
# 验证每个返回项
validated_items = []
for item in items:
try:
validated_item = SupplierDetailResponse.model_validate(item)
validated_items.append(validated_item)
except ValidationError as e:
print(f"⚠️ Skipping invalid supplier item: {e}")
continue
return validated_items, total