This commit is contained in:
Marsway 2026-03-04 12:35:28 +08:00
parent 90a54a8dd8
commit ecc79128f6
1 changed files with 62 additions and 4 deletions

View File

@ -46,6 +46,19 @@ def _custom_prop_value(custom_props: Any, key: str | None) -> str:
return str(raw or "").strip() return str(raw or "").strip()
def _to_bool_or_none(v: Any) -> bool | None:
if v is None:
return None
if isinstance(v, bool):
return v
s = str(v).strip().lower()
if s in ("1", "true", "yes", "y", "on"):
return True
if s in ("0", "false", "no", "n", "off", ""):
return False
return bool(v)
def _choose_better_record(current: dict[str, Any], candidate: dict[str, Any]) -> dict[str, Any]: def _choose_better_record(current: dict[str, Any], candidate: dict[str, Any]) -> dict[str, Any]:
def _score(item: dict[str, Any]) -> str: def _score(item: dict[str, Any]) -> str:
record = item.get("recordInfo") or {} record = item.get("recordInfo") or {}
@ -150,15 +163,43 @@ class SyncEhrToOaFormJob(BaseJob):
continue continue
existing = ehr_by_job_no.get(job_no) existing = ehr_by_job_no.get(job_no)
ehr_by_job_no[job_no] = item if existing is None else _choose_better_record(existing, item) ehr_by_job_no[job_no] = item if existing is None else _choose_better_record(existing, item)
logger.info(
"EHR 数据准备完成employee_rows=%s organization_rows=%s distinct_job_numbers=%s",
len(emp_rows),
len(org_rows),
len(ehr_by_job_no),
)
# 4) 导出 OA 表单,建立字段映射 + 工号到记录ID映射 # 4) 导出 OA 表单,建立字段映射 + 工号到记录ID映射
exp_resp = seeyon.export_cap4_form_soap(templateCode=oa_template_code, senderLoginName=sender_login_name, rightId=oa_right_id) exp_resp = seeyon.export_cap4_form_soap(
templateCode=oa_template_code,
senderLoginName=sender_login_name,
rightId=oa_right_id,
)
raw = exp_resp.text or "" raw = exp_resp.text or ""
logger.info(
"OA export 返回status=%s content_length=%s template=%s",
exp_resp.status_code,
len(raw),
oa_template_code,
)
if raw:
logger.info("OA export 响应预览:%s", raw[:1000])
try:
payload = json.loads(raw) if raw else {} payload = json.loads(raw) if raw else {}
except Exception as e: # noqa: BLE001
raise RuntimeError(f"OA export 响应不是有效 JSON: err={e!r} preview={raw[:500]!r}") from e
export_code = payload.get("code")
export_message = payload.get("message")
if export_code not in (None, 0, "0"):
raise RuntimeError(f"OA export failed code={export_code!r} message={export_message!r}")
outer = payload.get("data") or {} outer = payload.get("data") or {}
form = outer.get("data") or {} form = outer.get("data") or {}
if not isinstance(form, dict): if not isinstance(form, dict):
raise RuntimeError("OA export invalid: data.data is not an object") raise RuntimeError(
f"OA export invalid: data.data is not an object; payload_keys={list(payload.keys())[:20]}"
)
definition = form.get("definition") or {} definition = form.get("definition") or {}
fields = definition.get("fields") or [] fields = definition.get("fields") or []
@ -209,6 +250,12 @@ class SyncEhrToOaFormJob(BaseJob):
oa_master_table_name = str(master_tbl.get("name") or "").strip() oa_master_table_name = str(master_tbl.get("name") or "").strip()
if not oa_master_table_name: if not oa_master_table_name:
raise RuntimeError("public_cfg.oa_master_table_name is required (cannot infer from OA export)") raise RuntimeError("public_cfg.oa_master_table_name is required (cannot infer from OA export)")
logger.info(
"OA 表单解析完成template=%s master_table=%s form_rows=%s",
oa_template_code,
oa_master_table_name,
len(rows),
)
job_field_code = display_to_code["工号"] job_field_code = display_to_code["工号"]
oa_id_by_job_no: dict[str, int] = {} oa_id_by_job_no: dict[str, int] = {}
@ -234,6 +281,7 @@ class SyncEhrToOaFormJob(BaseJob):
except Exception: except Exception:
continue continue
oa_id_by_job_no[job_no] = row_id oa_id_by_job_no[job_no] = row_id
logger.info("OA 工号索引完成indexed_job_numbers=%s", len(oa_id_by_job_no))
# 5) 组装批量更新数据 # 5) 组装批量更新数据
data_list: list[dict[str, Any]] = [] data_list: list[dict[str, Any]] = []
@ -295,11 +343,21 @@ class SyncEhrToOaFormJob(BaseJob):
"subTables": [], "subTables": [],
} }
) )
logger.info(
"待更新数据准备完成prepared_updates=%s not_found_in_oa=%s",
len(data_list),
not_found_in_oa,
)
if not data_list:
raise RuntimeError(
"No updates prepared for OA batch-update (check jobNumber matching between EHR and OA, and form field mapping)"
)
# 6) 分批执行 batch-update # 6) 分批执行 batch-update
success_count = 0 success_count = 0
failed_count = 0 failed_count = 0
failed_data: dict[str, str] = {} failed_data: dict[str, str] = {}
do_trigger_bool = _to_bool_or_none(do_trigger)
for i in range(0, len(data_list), batch_size): for i in range(0, len(data_list), batch_size):
chunk = data_list[i : i + batch_size] chunk = data_list[i : i + batch_size]
resp = seeyon.batch_update_cap4_form_soap( resp = seeyon.batch_update_cap4_form_soap(
@ -308,7 +366,7 @@ class SyncEhrToOaFormJob(BaseJob):
rightId=oa_right_id, rightId=oa_right_id,
dataList=chunk, dataList=chunk,
uniqueFiled=[job_field_code], uniqueFiled=[job_field_code],
doTrigger=bool(do_trigger) if do_trigger is not None else None, doTrigger=do_trigger_bool,
) )
rj = resp.json() if resp.content else {} rj = resp.json() if resp.content else {}
code = int(rj.get("code", -1)) code = int(rj.get("code", -1))