1
0
forked from erp-dev/erp

feat: refactor flower.utils to sub package, added some sync api in package, added plate_order sync result model but relation of plate_order was not query (do it next step)

This commit is contained in:
2025-12-17 17:37:39 +08:00
parent 51fad953c3
commit 98d797221a
19 changed files with 1422 additions and 403 deletions

View File

@@ -0,0 +1,225 @@
from __future__ import annotations
from typing import Any
from asgiref.sync import sync_to_async
from .client import MDY_ENDPOINT_GET_FILTER_ROWS, get_default_mingdaoyun_client
from .mappings import (
MDY_WORKSHEET_ID_CUSTOMER,
MDY_WORKSHEET_ID_FABRIC,
MDY_WORKSHEET_ID_PLATE_ORDER,
MDY_WORKSHEET_ID_PRODUCT,
)
from .models import Customer, Fabric, Product
from .parsers import pick_customer, pick_fabric, pick_product
async def fetch_products_from_mingdaoyun(page: int = 1, page_size: int = 100) -> tuple[list[Product], int]:
"""从明道云获取产品列表"""
client = get_default_mingdaoyun_client()
response = await client.post(
endpoint=MDY_ENDPOINT_GET_FILTER_ROWS,
data={
"worksheetId": MDY_WORKSHEET_ID_PRODUCT,
"pageIndex": page,
"pageSize": page_size,
"sortId": "ctime",
"isAsc": True,
},
)
data = response.get("data") if isinstance(response, dict) else None
if data:
print(
f'[product-sync] page={page} size={page_size} rows={len(data.get("rows", []))} total={data.get("total")}'
)
else:
print(f"[product-sync] page={page} size={page_size} received empty 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 = get_default_mingdaoyun_client()
response = await client.post(
endpoint=MDY_ENDPOINT_GET_FILTER_ROWS,
data={
"worksheetId": MDY_WORKSHEET_ID_CUSTOMER,
"pageIndex": page,
"pageSize": page_size,
"sortId": "ctime",
"isAsc": True,
},
)
data = response.get("data") if isinstance(response, dict) else None
if data:
print(
f'[customer-sync] page={page} size={page_size} rows={len(data.get("rows", []))} total={data.get("total")}'
)
else:
print(f"[customer-sync] page={page} size={page_size} received empty 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
async def fetch_row_by_rowid_from_mingdaoyun(
worksheet_id: str,
rowid: str,
*,
sort_id: str = "ctime",
is_asc: bool = False,
list_type: int = 1,
not_get_total: bool = True,
data_type: int = 2,
filter_type: int = 3,
control_id: str = "rowId",
) -> dict[str, Any] | None:
"""按 rowId 查询工作表的单条记录(仅封装 rowId 等值查询)。
按照明道云 getFilterRows 的 filters 结构构造请求:
- dataType=2 表示字符串
- filterType=3 表示“相等”
返回:
- 匹配到记录:返回第一条 row dict
- 未匹配或响应无 data返回 None
"""
client = get_default_mingdaoyun_client()
response = await client.post(
endpoint=MDY_ENDPOINT_GET_FILTER_ROWS,
data={
"worksheetId": worksheet_id,
"listType": list_type,
"sortId": sort_id,
"isAsc": is_asc,
"notGetTotal": not_get_total,
"filters": [
{
"controlId": control_id,
"dataType": data_type,
"filterType": filter_type,
"value": rowid,
}
],
},
)
data = response.get("data") if isinstance(response, dict) else None
if not data:
return None
rows = data.get("rows") or []
if not rows:
return None
if isinstance(rows[0], dict):
return rows[0]
return None
async def fetch_plate_orders_from_mingdaoyun(
page: int = 1,
page_size: int = 100,
*,
sort_id: str = "ctime",
is_asc: bool = True,
) -> tuple[list[dict[str, Any]], int]:
"""从明道云获取“开版数据表”记录列表(原始行字典,不做字段映射解析)"""
client = get_default_mingdaoyun_client()
response = await client.post(
endpoint=MDY_ENDPOINT_GET_FILTER_ROWS,
data={
"worksheetId": MDY_WORKSHEET_ID_PLATE_ORDER,
"pageIndex": page,
"pageSize": page_size,
"sortId": sort_id,
"isAsc": is_asc,
},
)
data = response.get("data") if isinstance(response, dict) else None
if data:
print(
f'[plate-order-fetch] page={page} size={page_size} rows={len(data.get("rows", []))} total={data.get("total")}'
)
else:
print(f"[plate-order-fetch] page={page} size={page_size} received empty data")
if not data:
return [], 0
rows = data.get("rows", [])
total_count = data.get("total", 0)
return rows, total_count
async def sync_fabric_from_mingdaoyun(page: int = 1, page_size: int = 100) -> int:
"""从明道云同步面料数据(用于创建/更新 QuickInput: 布料名)"""
client = get_default_mingdaoyun_client()
response = await client.post(
endpoint=MDY_ENDPOINT_GET_FILTER_ROWS,
data={
"worksheetId": MDY_WORKSHEET_ID_FABRIC,
"pageIndex": page,
"pageSize": page_size,
"sortId": "ctime",
"isAsc": False,
},
)
data = response.get("data") if isinstance(response, dict) else None
if data:
rows = data.get("rows", [])
print(f"[fabric-sync] fetch rows={len(rows)} total={data.get('total')}")
if rows:
print(f"[fabric-sync] first row keys: {list(rows[0].keys())[:10]}")
print(f"[fabric-sync] first row sample: {rows[0]}")
else:
print(f"[fabric-sync] fetch empty data (page={page}, size={page_size})")
if not data:
return 0
fabrics = [pick_fabric(item) for item in data.get("rows", [])]
total_count = data.get("total", 0)
await sync_to_async(_create_fabric_quick_inputs)(
page,
page_size,
fabrics,
)
return total_count
def _create_fabric_quick_inputs(page: int, page_size: int, fabrics: list[Fabric]) -> None:
from basic_info import models as basic_models
total = len(fabrics)
created_count = 0
sample_names = [fabric.name for fabric in fabrics[:5]]
print(f"[fabric-sync] page={page} size={page_size} fetched={total}")
print(f"[fabric-sync] sample names: {sample_names}")
for fabric in fabrics:
if not fabric.name:
continue
obj, created = basic_models.QuickInput.objects.update_or_create(
name=fabric.name,
group="布料名",
defaults={"value": fabric.name},
)
if created:
created_count += 1
print(f"[fabric-sync] page={page} new_records={created_count} updated_or_existing={total - created_count}")