1
0
forked from erp-dev/erp
Files
erpnew/flower/utils.py

284 lines
7.3 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.
import aiohttp
from typing import Optional, Dict, Any, List
from pydantic import BaseModel, Field, computed_field
from enum import Enum
import json
class Product(BaseModel):
"""产品模型 - 请在此填入你的字段"""
uid: str
rowid: str
name: str
unit: str | None
color: str | None
width: str | None = None
detail_str: str | None = Field(exclude=True) # 在序列化时排除此字段
created_at: str
@computed_field
@property
def detail(self) -> dict[str, Any]:
"""将 detail_str 转换为字典"""
try:
return json.loads(self.detail_str) if self.detail_str else {}
except (json.JSONDecodeError, TypeError):
return {}
class ProductListResponse(BaseModel):
"""产品列表响应"""
products: List[Product]
total: int
mdy_table_map = {
'product': 'spmx',
'customer': 'quanbu',
}
class HTTPMethod(Enum):
"""HTTP 请求方法枚举"""
GET = "GET"
POST = "POST"
class MingDaoYunClient:
"""明道云 API 客户端"""
def __init__(self, app_key: str, sign: str, base_url: str = ""):
"""
初始化客户端
Args:
app_key: 应用密钥
sign: 签名
base_url: API 基础地址
"""
self.app_key = app_key
self.sign = sign
self.base_url = base_url
async def request(
self,
method: HTTPMethod,
endpoint: str,
data: Optional[Dict[str, Any]] = None,
params: Optional[Dict[str, Any]] = None,
headers: Optional[Dict[str, str]] = None,
) -> Any:
"""
通用异步请求函数
Args:
method: 请求方法 (GET/POST)
endpoint: API 端点路径
data: POST 请求体数据JSON
params: URL 查询参数
headers: 自定义请求头
Returns:
响应 JSON 数据
Raises:
aiohttp.ClientError: 请求失败时抛出
"""
url = f"{self.base_url}{endpoint}"
# 构建默认请求头
default_headers = {
"Content-Type": "application/json",
}
if headers:
default_headers.update(headers)
# 添加认证参数
auth_params = {
"appKey": self.app_key,
"sign": self.sign
}
async with aiohttp.ClientSession() as session:
if method == HTTPMethod.GET:
async with session.get(url, params=params, json=auth_params) as response:
response.raise_for_status()
return await response.json()
elif method == HTTPMethod.POST:
if data is None:
data = {}
data.update(auth_params)
async with session.post(url, json=data) as response:
response.raise_for_status()
return await response.json()
else:
raise ValueError(f"Unsupported HTTP method: {method}")
async def get(
self,
endpoint: str,
params: Optional[Dict[str, Any]] = None,
headers: Optional[Dict[str, str]] = None,
) -> Any:
"""
发送 GET 请求
Args:
endpoint: API 端点路径
params: URL 查询参数
headers: 自定义请求头
Returns:
响应 JSON 数据
"""
return await self.request(
method=HTTPMethod.GET,
endpoint=endpoint,
params=params,
headers=headers,
)
async def post(
self,
endpoint: str,
data: Optional[Dict[str, Any]] = None,
params: Optional[Dict[str, Any]] = None,
headers: Optional[Dict[str, str]] = None,
) -> Any:
"""
发送 POST 请求
Args:
endpoint: API 端点路径
data: POST 请求体数据JSON
params: URL 查询参数
headers: 自定义请求头
Returns:
响应 JSON 数据
"""
return await self.request(
method=HTTPMethod.POST,
endpoint=endpoint,
data=data,
params=params,
headers=headers,
)
product_type_map = {
'name': '668caa5eb80969563ecaee7d',
'color': '66ed3b9ae01d5599bdb45f6d',
'uid': '668caa5eb80969563ecaee7c',
'unit': '668e2ee2ca758c8cc5d0dc1d',
'width': '668e2194790c0e04058b4f3c',
'detail_str': '668caa5eb80969563ecaee7e',
'created_at': 'ctime',
'rowid': 'rowid',
}
customer_type_map = {
'name': '62d52f4b8d2972284492dcf9',
'area': '62d52f4b8d2972284492dd09',
'created_at': 'ctime',
'rowid': 'rowid',
'uid': '668bb9370207cf7520fe551e',
}
class Customer(BaseModel):
"""客户模型 - 请在此填入你的字段"""
uid: str
rowid: str
name: str
area: str | None
created_at: str
def pick_customer(fields: dict) -> Customer:
"""从字段字典中提取客户信息"""
data = {k: fields.get(v, '') for k, v in customer_type_map.items()}
return Customer(**data)
# json param example:
# {
# "appKey": "208e55fea5cea59f",
# "sign": "MWU0YmViYjkwZmM1ZDIzYzRiN2U3ZGQ4MmE4ZGNkMjc0MWM1ZmQ2ZjkwMjljODE4YmNkZTBhMzA0OTU2YzE2NA==",
# "worksheetId": "quanbu",
# "listType": 1,
# "sortId": "ctime",
# "isAsc": false,
# "notGetTotal": true
# }
def pick_product(fields: dict) -> Product:
"""
从字段字典中提取产品信息
"""
data = {k: fields.get(v, '') for k, v in product_type_map.items()}
return Product(**data)
async def fetch_products_from_mingdaoyun(page: int = 1, page_size: int = 100) -> tuple[list[Product], int]:
"""
从明道云获取产品列表
Returns:
tuple: (产品列表, 总数量)
"""
client = MingDaoYunClient(
app_key='208e55fea5cea59f',
sign='MWU0YmViYjkwZmM1ZDIzYzRiN2U3ZGQ4MmE4ZGNkMjc0MWM1ZmQ2ZjkwMjljODE4YmNkZTBhMzA0OTU2YzE2NA==',
base_url="https://api.mingdao.com"
)
response = await client.post(
endpoint='/v2/open/worksheet/getFilterRows',
data={
'worksheetId': 'spmx',
'pageIndex': page,
'pageSize': page_size,
'sortId': 'ctime',
'isAsc': False,
}
)
data = response.get('data')
if not data:
return [], 0
products = [pick_product(item) for item in data.get('rows', [])]
total_count = data.get('total', 0)
return products, total_count
async def fetch_customers_from_mingdaoyun(page: int = 1, page_size: int = 100) -> tuple[list[Customer], int]:
"""
从明道云获取客户列表
"""
client = MingDaoYunClient(
app_key='208e55fea5cea59f',
sign='MWU0YmViYjkwZmM1ZDIzYzRiN2U3ZGQ4MmE4ZGNkMjc0MWM1ZmQ2ZjkwMjljODE4YmNkZTBhMzA0OTU2YzE2NA==',
base_url="https://api.mingdao.com"
)
response = await client.post(
endpoint='/v2/open/worksheet/getFilterRows',
data={
'worksheetId': 'quanbu',
'pageIndex': page,
'pageSize': page_size,
'sortId': 'ctime',
'isAsc': False,
}
)
data = response.get('data')
if not data:
return [], 0
customers = [pick_customer(item) for item in data.get('rows', [])]
total_count = data.get('total', 0)
return customers, total_count