forked from erp-dev/erp
160 lines
4.5 KiB
Python
160 lines
4.5 KiB
Python
from __future__ import annotations
|
||
|
||
import json
|
||
from typing import Any
|
||
|
||
from .mappings import plate_order_related_field_definitions, plate_order_relation_control_map
|
||
|
||
|
||
def _json_loads_safe(value: str) -> Any:
|
||
try:
|
||
return json.loads(value)
|
||
except Exception:
|
||
return value
|
||
|
||
|
||
def normalize_mdy_value(value: Any) -> Any:
|
||
"""尽量把明道云返回的字符串 JSON 规范化为 Python 对象。
|
||
|
||
常见情况:
|
||
- Relation/Attachment 可能返回字符串形式的 "[]" / "[{...}]"
|
||
- 空值经常是 "[]"(字符串)
|
||
"""
|
||
|
||
if value is None:
|
||
return None
|
||
|
||
if isinstance(value, str):
|
||
s = value.strip()
|
||
if s == "[]":
|
||
return []
|
||
if (s.startswith("[") and s.endswith("]")) or (s.startswith("{") and s.endswith("}")):
|
||
return _json_loads_safe(s)
|
||
return value
|
||
|
||
return value
|
||
|
||
|
||
def extract_relation_rowids(value: Any) -> list[str]:
|
||
"""从 Relation 字段的 value 中提取 rowid 列表。
|
||
|
||
兼容形态:
|
||
- list[dict](常见:[{rowid,name,link}, ...])
|
||
- str(可能是 JSON 字符串数组,如 "[{...}]" 或 "[]";也可能是逗号分割 rowId)
|
||
- dict(单条)
|
||
"""
|
||
|
||
value = normalize_mdy_value(value)
|
||
|
||
if value is None:
|
||
return []
|
||
|
||
if isinstance(value, list):
|
||
out: list[str] = []
|
||
for item in value:
|
||
if isinstance(item, dict):
|
||
rid = item.get("rowid") or item.get("rowId")
|
||
if rid:
|
||
out.append(str(rid))
|
||
elif isinstance(item, str) and item.strip():
|
||
out.append(item.strip())
|
||
return out
|
||
|
||
if isinstance(value, dict):
|
||
rid = value.get("rowid") or value.get("rowId")
|
||
return [str(rid)] if rid else []
|
||
|
||
if isinstance(value, str):
|
||
s = value.strip()
|
||
if not s or s == "[]":
|
||
return []
|
||
# 兜底:逗号分割
|
||
return [x for x in (p.strip() for p in s.split(",")) if x]
|
||
|
||
return []
|
||
|
||
|
||
def extract_plate_order_related_rowids(plate_order_row: dict[str, Any]) -> dict[str, list[str]]:
|
||
"""从开版主表行记录中提取各关联表的 rowid 列表。
|
||
|
||
返回:
|
||
- {related_key: [rowid, ...], ...}
|
||
"""
|
||
|
||
result: dict[str, list[str]] = {}
|
||
for control_id, related_key in plate_order_relation_control_map.items():
|
||
rowids = extract_relation_rowids(plate_order_row.get(control_id))
|
||
if rowids:
|
||
result[related_key] = rowids
|
||
return result
|
||
|
||
|
||
def flatten_row_by_field_definitions(
|
||
row: dict[str, Any],
|
||
field_definitions: dict[str, dict[str, Any]],
|
||
*,
|
||
drop_types: set[str] | None = None,
|
||
drop_names: set[str] | None = None,
|
||
include_system_keys: bool = True,
|
||
) -> dict[str, Any]:
|
||
"""按字段定义把一条明道云 row 转成“可读 dict”。
|
||
|
||
- key 使用字段中文名(若缺失则回退 controlId)
|
||
- value 做一定的 JSON 字符串规范化
|
||
- 默认包含系统字段:rowid/ctime/utime(若存在)
|
||
"""
|
||
|
||
drop_types = drop_types or set()
|
||
drop_names = drop_names or set()
|
||
|
||
out: dict[str, Any] = {}
|
||
|
||
if include_system_keys:
|
||
for k in ("rowid", "ctime", "utime"):
|
||
if k in row:
|
||
out[k] = row.get(k)
|
||
|
||
for field_id, meta in field_definitions.items():
|
||
name = meta.get("name") or field_id
|
||
ftype = meta.get("type")
|
||
|
||
if ftype in drop_types:
|
||
continue
|
||
if name in drop_names:
|
||
continue
|
||
|
||
out[name] = normalize_mdy_value(row.get(field_id))
|
||
|
||
return out
|
||
|
||
|
||
def flatten_plate_order_related_row(related_key: str, related_row: dict[str, Any]) -> dict[str, Any]:
|
||
"""将开版关联表的一条 row 扁平化为 dict(用于入库 staging.related)。
|
||
|
||
- 自动删除回溯 Relation 字段(开版管理/开发管理等)
|
||
- 保留 rowid/ctime/utime(若存在)
|
||
- 额外写入 source 信息,便于排查
|
||
"""
|
||
|
||
meta = plate_order_related_field_definitions.get(related_key) or {}
|
||
wsid = meta.get("worksheet_id")
|
||
cn_name = meta.get("name")
|
||
fields = meta.get("fields") or {}
|
||
|
||
flat = flatten_row_by_field_definitions(
|
||
related_row,
|
||
fields,
|
||
drop_types={"Relation"},
|
||
drop_names={"开版管理", "开发管理"},
|
||
include_system_keys=True,
|
||
)
|
||
|
||
# 扁平化结构:[{key: val}, ...] 里的每个元素是一条记录
|
||
flat["source"] = related_key
|
||
if cn_name:
|
||
flat["source_name"] = cn_name
|
||
if wsid:
|
||
flat["worksheet_id"] = wsid
|
||
|
||
return flat
|